diff --git a/changelog b/changelog index 1fed804a7..a095a3967 100644 --- a/changelog +++ b/changelog @@ -5,6 +5,10 @@ * Grenade machinegun * 30rnd automatic 40mm grenade weapon firing at 120 RPS * Can be upgraded with an auxiliary electric engine to double the firerate +* Automatic thresher + * A specialized machine for automatically harvesting crops in a 7x7 area + * Replaces the buzzsaw's temporary functiionality to do just that (the buzzsaw now loses that ability) + * Drops harvested items using a chute instead of leaving them on the farmland ## Changed * RoR graphs can now have their min and max bounds set to a fixed number @@ -30,6 +34,7 @@ * Adjusted some 528 mode recipes * Removed the template crates entirely for being literally useless * Oil bubbles can no longer go down to Y:0, they now have a minimum center height of Y:15 +* The automatic buzzsaw and thresher now have sound loops when active ## Fixed * Fixed RoR graph showing the wrong name in the GUI diff --git a/src/main/java/com/hbm/blocks/machine/MachineThresher.java b/src/main/java/com/hbm/blocks/machine/MachineThresher.java index f4557d3b0..969c7ea84 100644 --- a/src/main/java/com/hbm/blocks/machine/MachineThresher.java +++ b/src/main/java/com/hbm/blocks/machine/MachineThresher.java @@ -14,6 +14,7 @@ import com.hbm.util.i18n.I18nUtil; import api.hbm.block.IToolable; import net.minecraft.block.BlockContainer; import net.minecraft.block.material.Material; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; @@ -21,6 +22,7 @@ import net.minecraft.util.ChatComponentText; import net.minecraft.util.ChatComponentTranslation; import net.minecraft.util.ChatStyle; import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.MathHelper; import net.minecraft.world.World; import net.minecraftforge.client.event.RenderGameOverlayEvent.Pre; @@ -62,6 +64,16 @@ public class MachineThresher extends BlockContainer implements ILookOverlay, ITo return true; } + + @Override + public void onBlockPlacedBy(World world, int x, int y, int z, EntityLivingBase player, ItemStack itemStack) { + int i = MathHelper.floor_double(player.rotationYaw * 4.0F / 360.0F + 0.5D) & 3; + + if(i == 0) world.setBlockMetadataWithNotify(x, y, z, 3, 2); + if(i == 1) world.setBlockMetadataWithNotify(x, y, z, 4, 2); + if(i == 2) world.setBlockMetadataWithNotify(x, y, z, 2, 2); + if(i == 3) world.setBlockMetadataWithNotify(x, y, z, 5, 2); + } @Override public boolean onScrew(World world, EntityPlayer player, int x, int y, int z, int side, float fX, float fY, float fZ, ToolType tool) { diff --git a/src/main/java/com/hbm/inventory/recipes/anvil/AnvilRecipes.java b/src/main/java/com/hbm/inventory/recipes/anvil/AnvilRecipes.java index 54bba8c4a..aa7a6e0be 100644 --- a/src/main/java/com/hbm/inventory/recipes/anvil/AnvilRecipes.java +++ b/src/main/java/com/hbm/inventory/recipes/anvil/AnvilRecipes.java @@ -407,6 +407,14 @@ public class AnvilRecipes extends SerializableRecipe { new ComparableStack(ModItems.sawblade) }, new AnvilOutput(new ItemStack(ModBlocks.machine_autosaw))).setTier(2)); + constructionRecipes.add(new AnvilConstructionRecipe( + new AStack[] { + new OreDictStack(STEEL.plate(), 8), + new OreDictStack(IRON.ingot(), 12), + new OreDictStack(CU.ingot(), 2), + new ComparableStack(ModItems.circuit, 1, EnumCircuitType.VACUUM_TUBE.ordinal()), + }, new AnvilOutput(new ItemStack(ModBlocks.machine_thresher))).setTier(2)); + /*constructionRecipes.add(new AnvilConstructionRecipe( new AStack[] { new OreDictStack(STEEL.ingot(), 6), diff --git a/src/main/java/com/hbm/render/tileentity/RenderThresher.java b/src/main/java/com/hbm/render/tileentity/RenderThresher.java index 3819a247f..3ebc6906e 100644 --- a/src/main/java/com/hbm/render/tileentity/RenderThresher.java +++ b/src/main/java/com/hbm/render/tileentity/RenderThresher.java @@ -22,19 +22,19 @@ public class RenderThresher extends TileEntitySpecialRenderer implements IItemRe GL11.glEnable(GL11.GL_CULL_FACE); switch(tile.getBlockMetadata()) { - case 3: GL11.glRotatef(270, 0F, 1F, 0F); break; - case 5: GL11.glRotatef(0, 0F, 1F, 0F); break; - case 2: GL11.glRotatef(90, 0F, 1F, 0F); break; - case 4: GL11.glRotatef(180, 0F, 1F, 0F); break; + case 3: GL11.glRotatef(180, 0F, 1F, 0F); break; + case 5: GL11.glRotatef(270, 0F, 1F, 0F); break; + case 2: GL11.glRotatef(0, 0F, 1F, 0F); break; + case 4: GL11.glRotatef(90, 0F, 1F, 0F); break; } TileEntityMachineThresher thresher = (TileEntityMachineThresher) tile; double angle = thresher.prevAngle + (thresher.angle - thresher.prevAngle) * interp; - double spin = thresher.lastSpin + (thresher.spin - thresher.spin) * interp; + double spin = thresher.lastSpin + (thresher.spin - thresher.lastSpin) * interp; double engine = thresher.isOn ? Math.sin(thresher.getWorldObj().getTotalWorldTime() * 2 % (Math.PI * 2) + interp) : 0; - renderCommon(82.5, spin, engine); + renderCommon(82.5 - angle, spin, engine); GL11.glPopMatrix(); } diff --git a/src/main/java/com/hbm/tileentity/machine/TileEntityMachineAutosaw.java b/src/main/java/com/hbm/tileentity/machine/TileEntityMachineAutosaw.java index 7c9e4bea3..70a04371d 100644 --- a/src/main/java/com/hbm/tileentity/machine/TileEntityMachineAutosaw.java +++ b/src/main/java/com/hbm/tileentity/machine/TileEntityMachineAutosaw.java @@ -15,8 +15,11 @@ import com.hbm.inventory.fluid.FluidType; import com.hbm.inventory.fluid.Fluids; import com.hbm.inventory.fluid.tank.FluidTank; import com.hbm.lib.ModDamageSource; +import com.hbm.main.MainRegistry; +import com.hbm.main.NTMSounds; import com.hbm.tileentity.IFluidCopiable; import com.hbm.packet.toclient.AuxParticlePacketNT; +import com.hbm.sound.AudioWrapper; import com.hbm.tileentity.IBufPacketReceiver; import com.hbm.tileentity.TileEntityLoadedBase; @@ -27,7 +30,6 @@ import cpw.mods.fml.relauncher.SideOnly; import io.netty.buffer.ByteBuf; import net.minecraft.block.Block; import net.minecraft.block.BlockLeaves; -import net.minecraft.block.IGrowable; import net.minecraft.block.material.Material; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityItem; @@ -88,6 +90,7 @@ public class TileEntityMachineAutosaw extends TileEntityLoadedBase implements IB public float spin; public float lastSpin; + private AudioWrapper audio; public TileEntityMachineAutosaw() { this.tank = new FluidTank(Fluids.WOODOIL, 100); @@ -231,6 +234,24 @@ public class TileEntityMachineAutosaw extends TileEntityLoadedBase implements IB worldObj.spawnParticle("smoke", xCoord + 0.5 + vec.xCoord, yCoord + 2.0625, zCoord + 0.5 + vec.zCoord, 0, 0, 0); } + + if(isOn && !isSuspended && MainRegistry.proxy.me().getDistanceSq(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5) < 15 * 15) { + if(audio == null) { + audio = createAudioLoop(); + audio.startSound(); + } else if(!audio.isPlaying()) { + audio = rebootAudio(audio); + } + + audio.keepAlive(); + audio.updateVolume(this.getVolume(1F)); + + } else { + if(audio != null) { + audio.stopSound(); + audio = null; + } + } if(this.spin >= 360F) { this.spin -= 360F; @@ -253,16 +274,33 @@ public class TileEntityMachineAutosaw extends TileEntityLoadedBase implements IB } } + @Override + public AudioWrapper createAudioLoop() { + return MainRegistry.proxy.getLoopedSound(NTMSounds.ENGINE_LOOP, xCoord, yCoord, zCoord, 1.0F, 10F, 1.0F + worldObj.rand.nextFloat() * 0.1F, 10); + } + + @Override + public void onChunkUnload() { + if(audio != null) { + audio.stopSound(); + audio = null; + } + } + + @Override + public void invalidate() { + super.invalidate(); + if(audio != null) { + audio.stopSound(); + audio = null; + } + } + /** Anything additionally that the detector nor the blades should pick up on, like non-mature willows */ public static boolean shouldIgnore(World world, int x, int y, int z, Block b, int meta) { if(b == ModBlocks.plant_tall) { return meta == EnumTallFlower.CD2.ordinal() + 8 || meta == EnumTallFlower.CD3.ordinal() + 8; } - - if((b instanceof IGrowable)) { - return ((IGrowable) b).func_149851_a(world, x, y, z, world.isRemote); - } - return false; } @@ -291,8 +329,6 @@ public class TileEntityMachineAutosaw extends TileEntityLoadedBase implements IB protected void cutCrop(int x, int y, int z) { - Block soil = worldObj.getBlock(x, y - 1, z); - Block b = worldObj.getBlock(x, y, z); int meta = worldObj.getBlockMetadata(x, y, z); @@ -303,19 +339,8 @@ public class TileEntityMachineAutosaw extends TileEntityLoadedBase implements IB if (!worldObj.isRemote && !worldObj.restoringBlockSnapshots) { ArrayList drops = b.getDrops(worldObj, x, y, z, meta, 0); - boolean replanted = false; for (ItemStack drop : drops) { - if (!replanted && drop.getItem() instanceof IPlantable) { - IPlantable seed = (IPlantable) drop.getItem(); - - if(soil.canSustainPlant(worldObj, x, y - 1, z, ForgeDirection.UP, seed)) { - replacementBlock = seed.getPlant(worldObj, x, y, z); - replacementMeta = seed.getPlantMetadata(worldObj, x, y, z); - replanted = true; - drop.stackSize -= 1; - } - } float delta = 0.7F; double dx = (double)(worldObj.rand.nextFloat() * delta) + (double)(1.0F - delta) * 0.5D; @@ -326,14 +351,6 @@ public class TileEntityMachineAutosaw extends TileEntityLoadedBase implements IB entityItem.delayBeforeCanPickup = 10; worldObj.spawnEntityInWorld(entityItem); } - - // Apparently, until 1.14 full-grown wheat could sometimes drop no seeds at all - // This is a quick and dirty workaround for that. - if (b == Blocks.wheat && !replanted) { - replacementBlock = b; - replacementMeta = 0; - replanted = true; - } } worldObj.setBlock(x, y, z, replacementBlock, replacementMeta, 3); diff --git a/src/main/java/com/hbm/tileentity/machine/TileEntityMachineThresher.java b/src/main/java/com/hbm/tileentity/machine/TileEntityMachineThresher.java index d1b139754..02fcaf73b 100644 --- a/src/main/java/com/hbm/tileentity/machine/TileEntityMachineThresher.java +++ b/src/main/java/com/hbm/tileentity/machine/TileEntityMachineThresher.java @@ -1,27 +1,40 @@ package com.hbm.tileentity.machine; import java.util.ArrayList; +import java.util.List; +import com.hbm.handler.threading.PacketThreading; import com.hbm.inventory.fluid.Fluids; import com.hbm.inventory.fluid.tank.FluidTank; +import com.hbm.lib.ModDamageSource; +import com.hbm.main.MainRegistry; +import com.hbm.main.NTMSounds; +import com.hbm.packet.toclient.AuxParticlePacketNT; +import com.hbm.sound.AudioWrapper; import com.hbm.tileentity.IBufPacketReceiver; import com.hbm.tileentity.IFluidCopiable; import com.hbm.tileentity.TileEntityLoadedBase; +import com.hbm.util.TrackerUtil; import api.hbm.fluidmk2.IFluidStandardReceiverMK2; +import cpw.mods.fml.common.network.NetworkRegistry.TargetPoint; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import io.netty.buffer.ByteBuf; import net.minecraft.block.Block; import net.minecraft.block.IGrowable; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.EntityTrackerEntry; import net.minecraft.entity.item.EntityItem; import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.play.server.S12PacketEntityVelocity; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.MathHelper; import net.minecraft.util.Vec3; import net.minecraft.world.World; +import net.minecraft.world.WorldServer; import net.minecraftforge.common.IPlantable; import net.minecraftforge.common.util.ForgeDirection; @@ -31,6 +44,7 @@ public class TileEntityMachineThresher extends TileEntityLoadedBase implements I public boolean isOn; public boolean isSuspended; + public int delay; private int turnProgress; public float syncAngle; @@ -42,6 +56,7 @@ public class TileEntityMachineThresher extends TileEntityLoadedBase implements I public float spin; public float lastSpin; + private AudioWrapper audio; public TileEntityMachineThresher() { this.tank = new FluidTank(Fluids.WOODOIL, 100); @@ -51,6 +66,91 @@ public class TileEntityMachineThresher extends TileEntityLoadedBase implements I public void updateEntity() { if(!worldObj.isRemote) { + + ForgeDirection dir = ForgeDirection.getOrientation(this.getBlockMetadata()).getOpposite(); + ForgeDirection rot = dir.getRotation(ForgeDirection.UP); + + if(!isSuspended && worldObj.getTotalWorldTime() % 20 == 0) { + if(tank.getFill() > 0) { + tank.setFill(tank.getFill() - 1); + this.isOn = true; + } else { + this.isOn = false; + } + + trySubscribe(tank.getTankType(), worldObj, xCoord + rot.offsetX, yCoord, zCoord + rot.offsetZ, rot); + trySubscribe(tank.getTankType(), worldObj, xCoord - rot.offsetX, yCoord, zCoord - rot.offsetZ, rot.getOpposite()); + } + + if(isOn && !isSuspended) { + + if(this.state == 0) { + this.delay--; + if(delay <= 0) this.state = 1; + } + + if(this.state == 1) { + this.angle += 82.5F / 60F; + + if(this.angle >= 82.5F) { + this.angle = 82.5F; + this.state = 2; + } + } else if(this.state == 2) { + this.angle -= 82.5F / 60F; + + if(this.angle <= 0F) { + this.angle = 0F; + this.state = 0; + this.delay = 200 + worldObj.rand.nextInt(100); + } + } + + if(this.angle != 0) { + Vec3 pivot = Vec3.createVectorHelper(xCoord + 0.5 + dir.offsetX, yCoord + 0.5, zCoord + 0.5); + Vec3 upperArm = Vec3.createVectorHelper(-dir.offsetX * 4, 0, -dir.offsetZ * 4); + upperArm.rotateAroundX((float) Math.toRadians(82.5 - angle)); + Vec3 lowerArm = Vec3.createVectorHelper(-dir.offsetX * 4, 0, -dir.offsetZ * 4); + lowerArm.rotateAroundX((float) -Math.toRadians(82.5 - angle)); + Vec3 armTip = Vec3.createVectorHelper(-dir.offsetX * 3, 0, -dir.offsetZ * 3); + + double endX = pivot.xCoord + upperArm.xCoord + lowerArm.xCoord + armTip.xCoord; + double endZ = pivot.zCoord + upperArm.zCoord + lowerArm.zCoord + armTip.zCoord; + + for(int i = -3; i <= 3; i++) { + int hitX = (int) Math.floor(endX + rot.offsetX * i); + int hitZ = (int) Math.floor(endZ + rot.offsetZ * i); + + Block b = worldObj.getBlock(hitX, yCoord, hitZ); + int meta = worldObj.getBlockMetadata(hitX, yCoord, hitZ); + + if(b.isNormalCube()) { + this.state = 2; + break; + } + + if(!this.shouldIgnore(worldObj, hitX, yCoord, hitZ, b, meta)) { + this.cutCrop(hitX, yCoord, hitZ); + } + } + + List affected = worldObj.getEntitiesWithinAABB(EntityLivingBase.class, AxisAlignedBB.getBoundingBox(endX, yCoord + 0.5, endZ, endX, yCoord + 0.5, endZ).expand(Math.abs(dir.offsetX * 0.5) + Math.abs(rot.offsetX * 4.5), 0.5, Math.abs(dir.offsetZ * 0.5) + Math.abs(rot.offsetZ * 4.5))); + + for(EntityLivingBase e : affected) { + if(e.isEntityAlive() && e.attackEntityFrom(ModDamageSource.turbofan, 100)) { + worldObj.playSoundEffect(e.posX, e.posY, e.posZ, "mob.zombie.woodbreak", 2.0F, 0.95F + worldObj.rand.nextFloat() * 0.2F); + int count = Math.min((int)Math.ceil(e.getMaxHealth() / 4), 250); + NBTTagCompound data = new NBTTagCompound(); + data.setString("type", "vanillaburst"); + data.setInteger("count", count * 4); + data.setDouble("motion", 0.1D); + data.setString("mode", "blockdust"); + data.setInteger("block", Block.getIdFromBlock(Blocks.redstone_block)); + PacketThreading.createAllAroundThreadedPacket(new AuxParticlePacketNT(data, e.posX, e.posY + e.height * 0.5, e.posZ), new TargetPoint(e.dimension, e.posX, e.posY, e.posZ, 50)); + } + } + } + } networkPackNT(100); @@ -59,12 +159,30 @@ public class TileEntityMachineThresher extends TileEntityLoadedBase implements I this.lastSpin = this.spin; if(isOn && !isSuspended) { - this.spin += 15F; + if(this.angle > 0) this.spin += 15F; + + ForgeDirection dir = ForgeDirection.getOrientation(this.getBlockMetadata()).getOpposite(); + ForgeDirection rot = dir.getRotation(ForgeDirection.UP); - Vec3 vec = Vec3.createVectorHelper(0.625, 0, 1.625); - vec.rotateAroundY(-(float) Math.toRadians(angle)); + worldObj.spawnParticle("smoke", xCoord + 0.5 + dir.offsetX * 0.8125 + rot.offsetX * 0.375, yCoord + 1.5625, zCoord + 0.5 + dir.offsetZ * 0.8125 + rot.offsetZ * 0.375, 0, 0, 0); + } + + if(isOn && !isSuspended && MainRegistry.proxy.me().getDistanceSq(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5) < 15 * 15) { + if(audio == null) { + audio = createAudioLoop(); + audio.startSound(); + } else if(!audio.isPlaying()) { + audio = rebootAudio(audio); + } - worldObj.spawnParticle("smoke", xCoord + 0.5 + vec.xCoord, yCoord + 2.0625, zCoord + 0.5 + vec.zCoord, 0, 0, 0); + audio.keepAlive(); + audio.updateVolume(this.getVolume(1F)); + + } else { + if(audio != null) { + audio.stopSound(); + audio = null; + } } if(this.spin >= 360F) { @@ -84,6 +202,28 @@ public class TileEntityMachineThresher extends TileEntityLoadedBase implements I } } + @Override + public AudioWrapper createAudioLoop() { + return MainRegistry.proxy.getLoopedSound(NTMSounds.ENGINE_LOOP, xCoord, yCoord, zCoord, 1.0F, 10F, 1.0F + worldObj.rand.nextFloat() * 0.1F, 10); + } + + @Override + public void onChunkUnload() { + if(audio != null) { + audio.stopSound(); + audio = null; + } + } + + @Override + public void invalidate() { + super.invalidate(); + if(audio != null) { + audio.stopSound(); + audio = null; + } + } + public static boolean shouldIgnore(World world, int x, int y, int z, Block b, int meta) { if((b instanceof IGrowable)) { @@ -119,15 +259,20 @@ public class TileEntityMachineThresher extends TileEntityLoadedBase implements I drop.stackSize -= 1; } } + + ForgeDirection dir = ForgeDirection.getOrientation(this.getBlockMetadata()); + double spawnX = xCoord + 0.5 - dir.offsetX * 0.75; + double spawnZ = zCoord + 0.5 - dir.offsetZ * 0.75; - float delta = 0.7F; - double dx = (double)(worldObj.rand.nextFloat() * delta) + (double)(1.0F - delta) * 0.5D; - double dy = (double)(worldObj.rand.nextFloat() * delta) + (double)(1.0F - delta) * 0.5D; - double dz = (double)(worldObj.rand.nextFloat() * delta) + (double)(1.0F - delta) * 0.5D; - - EntityItem entityItem = new EntityItem(worldObj, x + dx, y + dy, z + dz, drop); + EntityItem entityItem = new EntityItem(worldObj, spawnX, yCoord, spawnZ, drop); entityItem.delayBeforeCanPickup = 10; worldObj.spawnEntityInWorld(entityItem); + + entityItem.motionX = dir.offsetX * -0.2 + 0.2; + entityItem.motionZ = dir.offsetZ * -0.2; + EntityTrackerEntry entry = TrackerUtil.getTrackerEntry((WorldServer) worldObj, entityItem.getEntityId()); + entry.func_151259_a(new S12PacketEntityVelocity(entityItem.getEntityId(), entityItem.motionX, entityItem.motionY, entityItem.motionZ)); + } // Apparently, until 1.14 full-grown wheat could sometimes drop no seeds at all diff --git a/src/main/resources/assets/hbm/lang/de_DE.lang b/src/main/resources/assets/hbm/lang/de_DE.lang index 029108551..08d51d270 100644 --- a/src/main/resources/assets/hbm/lang/de_DE.lang +++ b/src/main/resources/assets/hbm/lang/de_DE.lang @@ -4404,7 +4404,7 @@ tile.machine_assembly_factory.name=Fertigungsfabrik tile.machine_assembly_machine.name=Montagemaschine tile.machine_autocrafter.name=Automatische Werkbank tile.machine_autosaw.name=Automatische Kreissäge -tile.machine_autosaw.desc=Schneidet Pflanzen nieder, pflanzt Bäume nach$Akzeptiert:$-Holzöl$-Ethanol$-Fischöl$-Schweröl +tile.machine_autosaw.desc=Schneidet Pflanzen nieder, pflanzt Bäume nach$Akzeptiert:$-Holzöl$-Ethanol$-Fischöl$-Schweröl$-Kohleteer-Kreosot tile.machine_autosaw.suspended=Angehalten tile.machine_bat9000.name=Big-Ass Tank 9000 tile.machine_battery.name=Energiespeicherblock (LEGACY) @@ -4548,6 +4548,9 @@ tile.machine_stirling_steel.desc=Erzeugt Energie aus Wärme. Benötigt externe H tile.machine_storage_drum.name=Atommüll-Lagertrommel tile.machine_telelinker.name=Geschütz-Telemetrie-Manager tile.machine_teleporter.name=Teleporter +tile.machine_thresher.name=Automatischer Mähdrescher +tile.machine_thresher.desc=Erntet Feldpflanzen und pflanzt sie nach.$Akzeptiert:$-Holzöl$-Ethanol$-Fischöl$-Schweröl$-Kohleteer-Kreosot +tile.machine_thresher.suspended=Angehalten tile.machine_tower_large.name=Kühlturm tile.machine_tower_small.name=Hilfskühlturm tile.machine_transformer.name=10k-20Hz-Transformator diff --git a/src/main/resources/assets/hbm/lang/en_US.lang b/src/main/resources/assets/hbm/lang/en_US.lang index ddfec4a7a..033f9973c 100644 --- a/src/main/resources/assets/hbm/lang/en_US.lang +++ b/src/main/resources/assets/hbm/lang/en_US.lang @@ -5802,6 +5802,9 @@ tile.machine_storage_drum.name=Nuclear Waste Disposal Drum tile.machine_strand_caster.name=Strand Caster tile.machine_telelinker.name=Turret Telemetry Linker tile.machine_teleporter.name=Teleporter +tile.machine_thresher.name=Automatic Thresher +tile.machine_thresher.desc=Harvests and re-plants crops.$Accepts:$-Wood oil$-Ethanol$-Fish oil$-Heavy oil$-Coal Tar Creosote +tile.machine_thresher.suspended=Suspended tile.machine_tower_large.name=Cooling Tower tile.machine_tower_small.name=Auxiliary Cooling Tower tile.machine_transformer.name=10k-20Hz Transformer