From a247a80d5368d083d3e14880669f013a2385894b Mon Sep 17 00:00:00 2001 From: aidancbrady Date: Sun, 6 Mar 2016 17:53:16 -0500 Subject: [PATCH] Work on Formulaic Assemblicator, got a lot more of the core logic done than I was expecting to --- .../java/mekanism/api/MekanismConfig.java | 1 + .../mekanism/common/block/BlockMachine.java | 8 +- .../content/assemblicator/RecipeFormula.java | 104 ++++ .../common/item/ItemControlCircuit.java | 2 - .../common/item/ItemRecipeFormula.java | 17 + .../TileEntityFormulaicAssemblicator.java | 454 ++++++++++++++++++ .../tile/TileEntityLaserTractorBeam.java | 3 +- .../tile/TileEntityResistiveHeater.java | 6 + .../mekanism/common/util/MekanismUtils.java | 16 +- .../mekanism/common/util/RecipeUtils.java | 14 + .../gui/GuiFormulaicAssemblicator.png | Bin 0 -> 6824 bytes .../mekanism/gui/GuiUpgradeManagement.png | Bin 5248 -> 5277 bytes .../resources/assets/mekanism/lang/en_US.lang | 1 + 13 files changed, 619 insertions(+), 7 deletions(-) create mode 100644 src/main/java/mekanism/common/content/assemblicator/RecipeFormula.java create mode 100644 src/main/java/mekanism/common/item/ItemRecipeFormula.java create mode 100644 src/main/java/mekanism/common/tile/TileEntityFormulaicAssemblicator.java create mode 100644 src/main/resources/assets/mekanism/gui/GuiFormulaicAssemblicator.png diff --git a/src/main/java/mekanism/api/MekanismConfig.java b/src/main/java/mekanism/api/MekanismConfig.java index fe85beeb3..dae1fc598 100644 --- a/src/main/java/mekanism/api/MekanismConfig.java +++ b/src/main/java/mekanism/api/MekanismConfig.java @@ -122,6 +122,7 @@ public class MekanismConfig public static double laserUsage; public static double gasCentrifugeUsage; public static double heavyWaterElectrolysisUsage; + public static double formulaicAssemblicatorUsage; } public static class generators diff --git a/src/main/java/mekanism/common/block/BlockMachine.java b/src/main/java/mekanism/common/block/BlockMachine.java index 434b4a499..004c12e76 100644 --- a/src/main/java/mekanism/common/block/BlockMachine.java +++ b/src/main/java/mekanism/common/block/BlockMachine.java @@ -66,6 +66,7 @@ import mekanism.common.tile.TileEntityEnrichmentChamber; import mekanism.common.tile.TileEntityFactory; import mekanism.common.tile.TileEntityFluidTank; import mekanism.common.tile.TileEntityFluidicPlenisher; +import mekanism.common.tile.TileEntityFormulaicAssemblicator; import mekanism.common.tile.TileEntityLaser; import mekanism.common.tile.TileEntityLaserAmplifier; import mekanism.common.tile.TileEntityLaserTractorBeam; @@ -1172,7 +1173,8 @@ public class BlockMachine extends BlockContainer implements ISpecialBounds, IBlo SOLAR_NEUTRON_ACTIVATOR(MachineBlock.MACHINE_BLOCK_3, 1, "SolarNeutronActivator", 47, TileEntitySolarNeutronActivator.class, false, true, false), AMBIENT_ACCUMULATOR(MachineBlock.MACHINE_BLOCK_3, 2, "AmbientAccumulator", 48, TileEntityAmbientAccumulator.class, true, false, false), OREDICTIONIFICATOR(MachineBlock.MACHINE_BLOCK_3, 3, "Oredictionificator", 52, TileEntityOredictionificator.class, false, false, false), - RESISTIVE_HEATER(MachineBlock.MACHINE_BLOCK_3, 4, "ResistiveHeater", 53, TileEntityResistiveHeater.class, true, false, false); + RESISTIVE_HEATER(MachineBlock.MACHINE_BLOCK_3, 4, "ResistiveHeater", 53, TileEntityResistiveHeater.class, true, false, false), + FORMULAIC_ASSEMBLICATOR(MachineBlock.MACHINE_BLOCK_3, 5, "FormulaicAssemblicator", 56, TileEntityFormulaicAssemblicator.class, true, false, true); public MachineBlock typeBlock; public int meta; @@ -1223,7 +1225,7 @@ public class BlockMachine extends BlockContainer implements ISpecialBounds, IBlo for(MachineType type : MachineType.values()) { - if(type != AMBIENT_ACCUMULATOR) + if(type != AMBIENT_ACCUMULATOR && type != FORMULAIC_ASSEMBLICATOR) { ret.add(type); } @@ -1343,6 +1345,8 @@ public class BlockMachine extends BlockContainer implements ISpecialBounds, IBlo return 0; case RESISTIVE_HEATER: return 100; + case FORMULAIC_ASSEMBLICATOR: + return usage.formulaicAssemblicatorUsage; default: return 0; } diff --git a/src/main/java/mekanism/common/content/assemblicator/RecipeFormula.java b/src/main/java/mekanism/common/content/assemblicator/RecipeFormula.java new file mode 100644 index 000000000..84ea25418 --- /dev/null +++ b/src/main/java/mekanism/common/content/assemblicator/RecipeFormula.java @@ -0,0 +1,104 @@ +package mekanism.common.content.assemblicator; + +import mekanism.api.util.StackUtils; +import mekanism.common.util.MekanismUtils; +import mekanism.common.util.RecipeUtils; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.world.World; + +public class RecipeFormula +{ + public InventoryCrafting dummy = MekanismUtils.getDummyCraftingInv(); + + public ItemStack[] input = new ItemStack[9]; + + public RecipeFormula(ItemStack[] inv) + { + this(inv, 0); + } + + public RecipeFormula(ItemStack[] inv, int start) + { + for(int i = 0; i < 9; i++) + { + input[i] = StackUtils.size(inv[start+i], 1); + } + } + + private void resetToRecipe() + { + for(int i = 0; i < 9; i++) + { + dummy.setInventorySlotContents(i, input[i]); + } + } + + public boolean matches(World world, ItemStack[] input, int start) + { + resetToRecipe(); + + IRecipe origRecipe = RecipeUtils.getRecipeFromGrid(dummy, world); + + for(int i = 0; i < 9; i++) + { + dummy.setInventorySlotContents(i, input[start+i]); + } + + IRecipe newRecipe = RecipeUtils.getRecipeFromGrid(dummy, world); + + return origRecipe == newRecipe; + } + + public boolean isIngredientInPos(World world, ItemStack stack, int i) + { + resetToRecipe(); + + IRecipe origRecipe = RecipeUtils.getRecipeFromGrid(dummy, world); + dummy.setInventorySlotContents(i, stack); + IRecipe newRecipe = RecipeUtils.getRecipeFromGrid(dummy, world); + + return origRecipe == newRecipe; + } + + public boolean isIngredient(World world, ItemStack stack) + { + resetToRecipe(); + + IRecipe origRecipe = RecipeUtils.getRecipeFromGrid(dummy, world); + + for(int i = 0; i < 9; i++) + { + dummy.setInventorySlotContents(i, stack); + + IRecipe newRecipe = RecipeUtils.getRecipeFromGrid(dummy, world); + + if(origRecipe == newRecipe) + { + return true; + } + + dummy.setInventorySlotContents(i, input[i]); + } + + return false; + } + + public boolean isValidFormula(World world) + { + return getRecipe(world) != null; + } + + public IRecipe getRecipe(World world) + { + resetToRecipe(); + + return RecipeUtils.getRecipeFromGrid(dummy, world); + } + + public boolean isFormulaEqual(World world, RecipeFormula formula) + { + return formula.getRecipe(world) == getRecipe(world); + } +} diff --git a/src/main/java/mekanism/common/item/ItemControlCircuit.java b/src/main/java/mekanism/common/item/ItemControlCircuit.java index 5d8d94c08..40f14426a 100644 --- a/src/main/java/mekanism/common/item/ItemControlCircuit.java +++ b/src/main/java/mekanism/common/item/ItemControlCircuit.java @@ -2,7 +2,6 @@ package mekanism.common.item; import java.util.List; -import mekanism.common.Mekanism; import mekanism.common.Tier.BaseTier; import net.minecraft.client.renderer.texture.IIconRegister; import net.minecraft.creativetab.CreativeTabs; @@ -18,7 +17,6 @@ public class ItemControlCircuit extends ItemMekanism { super(); setHasSubtypes(true); - setCreativeTab(Mekanism.tabMekanism); } @Override diff --git a/src/main/java/mekanism/common/item/ItemRecipeFormula.java b/src/main/java/mekanism/common/item/ItemRecipeFormula.java new file mode 100644 index 000000000..624e875ad --- /dev/null +++ b/src/main/java/mekanism/common/item/ItemRecipeFormula.java @@ -0,0 +1,17 @@ +package mekanism.common.item; + +import net.minecraft.item.ItemStack; + +public class ItemRecipeFormula extends ItemMekanism +{ + public ItemRecipeFormula() + { + super(); + } + + @Override + public int getItemStackLimit(ItemStack stack) + { + return 1; + } +} diff --git a/src/main/java/mekanism/common/tile/TileEntityFormulaicAssemblicator.java b/src/main/java/mekanism/common/tile/TileEntityFormulaicAssemblicator.java new file mode 100644 index 000000000..4e50cf3a0 --- /dev/null +++ b/src/main/java/mekanism/common/tile/TileEntityFormulaicAssemblicator.java @@ -0,0 +1,454 @@ +package mekanism.common.tile; + +import io.netty.buffer.ByteBuf; + +import java.util.ArrayList; + +import mekanism.api.EnumColor; +import mekanism.api.IConfigCardAccess; +import mekanism.api.MekanismConfig.usage; +import mekanism.api.transmitters.TransmissionType; +import mekanism.api.util.StackUtils; +import mekanism.common.SideData; +import mekanism.common.Upgrade; +import mekanism.common.base.IRedstoneControl; +import mekanism.common.base.ISideConfiguration; +import mekanism.common.base.IUpgradeTile; +import mekanism.common.block.BlockMachine.MachineType; +import mekanism.common.content.assemblicator.RecipeFormula; +import mekanism.common.item.ItemRecipeFormula; +import mekanism.common.tile.component.TileComponentConfig; +import mekanism.common.tile.component.TileComponentEjector; +import mekanism.common.tile.component.TileComponentUpgrade; +import mekanism.common.util.ChargeUtils; +import mekanism.common.util.InventoryUtils; +import mekanism.common.util.MekanismUtils; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +public class TileEntityFormulaicAssemblicator extends TileEntityElectricBlock implements ISideConfiguration, IUpgradeTile, IRedstoneControl, IConfigCardAccess +{ + public InventoryCrafting dummyInv = MekanismUtils.getDummyCraftingInv(); + + public double BASE_ENERGY_PER_TICK = usage.metallurgicInfuserUsage; + + public double energyPerTick = BASE_ENERGY_PER_TICK; + + public int BASE_TICKS_REQUIRED = 100; + + public int ticksRequired = BASE_TICKS_REQUIRED; + + public int operatingTicks; + + public boolean autoMode = false; + + public RecipeFormula formula; + + public RedstoneControl controlType = RedstoneControl.DISABLED; + + public TileComponentUpgrade upgradeComponent; + public TileComponentEjector ejectorComponent; + public TileComponentConfig configComponent; + + public TileEntityFormulaicAssemblicator() + { + super("FormulaicAssemblicator", MachineType.FORMULAIC_ASSEMBLICATOR.baseEnergy); + + configComponent = new TileComponentConfig(this, TransmissionType.ITEM, TransmissionType.ENERGY); + + configComponent.addOutput(TransmissionType.ITEM, new SideData("None", EnumColor.GREY, InventoryUtils.EMPTY)); + configComponent.addOutput(TransmissionType.ITEM, new SideData("Input", EnumColor.DARK_RED, + new int[] {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20})); + configComponent.addOutput(TransmissionType.ITEM, new SideData("Output", EnumColor.DARK_BLUE, new int[] {21, 22, 23, 24, 25, 26})); + configComponent.addOutput(TransmissionType.ITEM, new SideData("Energy", EnumColor.DARK_GREEN, new int[] {1})); + + configComponent.setConfig(TransmissionType.ITEM, new byte[] {0, 0, 0, 3, 1, 2}); + configComponent.setInputConfig(TransmissionType.ENERGY); + + inventory = new ItemStack[35]; + + upgradeComponent = new TileComponentUpgrade(this, 0); + + ejectorComponent = new TileComponentEjector(this); + ejectorComponent.setOutputData(TransmissionType.ITEM, configComponent.getOutputs(TransmissionType.ITEM).get(2)); + } + + @Override + public void onUpdate() + { + super.onUpdate(); + + if(!worldObj.isRemote) + { + ChargeUtils.discharge(1, this); + + if(inventory[2] != null && inventory[2].getItem() instanceof ItemRecipeFormula) + { + + } + else { + formula = null; + } + + if(autoMode && formula != null) + { + boolean canOperate = true; + + if(!formula.matches(worldObj, inventory, 27)) + { + canOperate = moveItemsToGrid(); + } + + if(canOperate) + { + if(operatingTicks == ticksRequired) + { + if(MekanismUtils.canFunction(this)) + { + doSingleCraft(); + } + } + else { + if(getEnergy() >= energyPerTick) + { + operatingTicks++; + setEnergy(getEnergy() - energyPerTick); + } + } + } + else { + operatingTicks = 0; + } + } + else { + operatingTicks = 0; + } + } + } + + private boolean doSingleCraft() + { + for(int i = 0; i < 9; i++) + { + dummyInv.setInventorySlotContents(i, inventory[27+i]); + } + + ItemStack output = MekanismUtils.findMatchingRecipe(dummyInv, worldObj); + + if(output != null && tryMoveToOutput(output, false)) + { + tryMoveToOutput(output, true); + + for(int i = 27; i <= 35; i++) + { + inventory[i].stackSize--; + + if(inventory[i].stackSize == 0) + { + inventory[i] = null; + } + } + + return true; + } + + return false; + } + + private boolean craftSingle() + { + if(formula != null) + { + boolean canOperate = false; + + if(!formula.matches(worldObj, inventory, 27)) + { + canOperate = moveItemsToGrid(); + } + + if(canOperate) + { + doSingleCraft(); + } + } + else { + doSingleCraft(); + } + + return false; + } + + private boolean moveItemsToGrid() + { + for(int i = 27; i <= 35; i++) + { + if(formula.isIngredientInPos(worldObj, inventory[i], i-27)) + { + continue; + } + + if(inventory[i] != null) + { + inventory[i] = tryMoveToInput(inventory[i]); + + if(inventory[i] != null) + { + return false; + } + } + else { + boolean found = false; + + for(int j = 3; j <= 20; j++) + { + if(inventory[j] != null && formula.isIngredientInPos(worldObj, inventory[j], i-27)) + { + inventory[i] = StackUtils.size(inventory[j], 1); + inventory[j].stackSize--; + + if(inventory[j].stackSize == 0) + { + inventory[j] = null; + } + + found = true; + + break; + } + } + + if(!found) + { + return false; + } + } + } + + return true; + } + + private void craftAll() + { + while(craftSingle()); + } + + private void toggleAutoMode() + { + if(autoMode) + { + operatingTicks = 0; + autoMode = false; + } + else { + for(int i = 27; i <= 35; i++) + { + inventory[i] = tryMoveToInput(inventory[i]); + } + + autoMode = true; + } + } + + private ItemStack tryMoveToInput(ItemStack stack) + { + stack = stack.copy(); + + for(int i = 3; i <= 20; i++) + { + if(inventory[i] == null) + { + inventory[i] = stack; + + return null; + } + else if(InventoryUtils.areItemsStackable(stack, inventory[i]) && inventory[i].stackSize < inventory[i].getMaxStackSize()) + { + int toUse = Math.min(stack.stackSize, inventory[i].getMaxStackSize()-inventory[i].stackSize); + + inventory[i].stackSize += toUse; + stack.stackSize -= toUse; + + if(stack.stackSize == 0) + { + return null; + } + } + } + + return stack; + } + + private boolean tryMoveToOutput(ItemStack stack, boolean doMove) + { + stack = stack.copy(); + + for(int i = 21; i <= 26; i++) + { + if(inventory[i] == null) + { + if(doMove) + { + inventory[i] = stack; + } + + return true; + } + else if(InventoryUtils.areItemsStackable(stack, inventory[i]) && inventory[i].stackSize < inventory[i].getMaxStackSize()) + { + int toUse = Math.min(stack.stackSize, inventory[i].getMaxStackSize()-inventory[i].stackSize); + + if(doMove) + { + inventory[i].stackSize += toUse; + } + + stack.stackSize -= toUse; + + if(stack.stackSize == 0) + { + return true; + } + } + } + + return false; + } + + private void encodeFormula() + { + + } + + @Override + public boolean canSetFacing(int side) + { + return side != 0 && side != 1; + } + + @Override + public void readFromNBT(NBTTagCompound nbtTags) + { + super.readFromNBT(nbtTags); + + autoMode = nbtTags.getBoolean("autoMode"); + operatingTicks = nbtTags.getInteger("operatingTicks"); + controlType = RedstoneControl.values()[nbtTags.getInteger("controlType")]; + } + + @Override + public void writeToNBT(NBTTagCompound nbtTags) + { + super.writeToNBT(nbtTags); + + nbtTags.setBoolean("autoMode", autoMode); + nbtTags.setInteger("operatingTicks", operatingTicks); + nbtTags.setInteger("controlType", controlType.ordinal()); + } + + @Override + public void handlePacketData(ByteBuf dataStream) + { + if(!worldObj.isRemote) + { + int type = dataStream.readInt(); + + if(type == 0) + { + toggleAutoMode(); + } + else if(type == 1) + { + encodeFormula(); + } + else if(type == 2) + { + craftSingle(); + } + else if(type == 3) + { + craftAll(); + } + + return; + } + + super.handlePacketData(dataStream); + + autoMode = dataStream.readBoolean(); + operatingTicks = dataStream.readInt(); + controlType = RedstoneControl.values()[dataStream.readInt()]; + } + + @Override + public ArrayList getNetworkedData(ArrayList data) + { + super.getNetworkedData(data); + + data.add(autoMode); + data.add(operatingTicks); + data.add(controlType.ordinal()); + + return data; + } + + @Override + public RedstoneControl getControlType() + { + return controlType; + } + + @Override + public void setControlType(RedstoneControl type) + { + controlType = type; + MekanismUtils.saveChunk(this); + } + + @Override + public boolean canPulse() + { + return true; + } + + @Override + public TileComponentConfig getConfig() + { + return configComponent; + } + + @Override + public int getOrientation() + { + return facing; + } + + @Override + public TileComponentUpgrade getComponent() + { + return upgradeComponent; + } + + @Override + public TileComponentEjector getEjector() + { + return ejectorComponent; + } + + @Override + public void recalculateUpgradables(Upgrade upgrade) + { + super.recalculateUpgradables(upgrade); + + switch(upgrade) + { + case SPEED: + ticksRequired = MekanismUtils.getTicks(this, BASE_TICKS_REQUIRED); + case ENERGY: + energyPerTick = MekanismUtils.getEnergyPerTick(this, BASE_ENERGY_PER_TICK); + maxEnergy = MekanismUtils.getMaxEnergy(this, BASE_MAX_ENERGY); + default: + break; + } + } +} diff --git a/src/main/java/mekanism/common/tile/TileEntityLaserTractorBeam.java b/src/main/java/mekanism/common/tile/TileEntityLaserTractorBeam.java index 48d0599d9..574439892 100644 --- a/src/main/java/mekanism/common/tile/TileEntityLaserTractorBeam.java +++ b/src/main/java/mekanism/common/tile/TileEntityLaserTractorBeam.java @@ -86,8 +86,7 @@ public class TileEntityLaserTractorBeam extends TileEntityContainerBlock impleme } } - else - { + else { if(collectedEnergy > 0) { double firing = collectedEnergy; diff --git a/src/main/java/mekanism/common/tile/TileEntityResistiveHeater.java b/src/main/java/mekanism/common/tile/TileEntityResistiveHeater.java index e01795d1c..3442c4785 100644 --- a/src/main/java/mekanism/common/tile/TileEntityResistiveHeater.java +++ b/src/main/java/mekanism/common/tile/TileEntityResistiveHeater.java @@ -115,6 +115,12 @@ public class TileEntityResistiveHeater extends TileEntityNoisyElectricBlock impl } } + @Override + public boolean canSetFacing(int side) + { + return side != 0 && side != 1; + } + @Override public float getVolume() { diff --git a/src/main/java/mekanism/common/util/MekanismUtils.java b/src/main/java/mekanism/common/util/MekanismUtils.java index a34668dbc..0ddea9d88 100644 --- a/src/main/java/mekanism/common/util/MekanismUtils.java +++ b/src/main/java/mekanism/common/util/MekanismUtils.java @@ -62,6 +62,7 @@ import net.minecraft.client.gui.FontRenderer; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Blocks; +import net.minecraft.inventory.Container; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.InventoryCrafting; import net.minecraft.item.Item; @@ -1355,9 +1356,22 @@ public final class MekanismUtils return tank; } + + public static InventoryCrafting getDummyCraftingInv() + { + Container tempContainer = new Container() { + @Override + public boolean canInteractWith(EntityPlayer player) + { + return false; + } + }; + + return new InventoryCrafting(tempContainer, 3, 3); + } /** - * Finds the output of a defined InventoryCrafting grid. Taken from CofhCore. + * Finds the output of a defined InventoryCrafting grid. * @param inv - InventoryCrafting to check * @param world - world reference * @return output ItemStack diff --git a/src/main/java/mekanism/common/util/RecipeUtils.java b/src/main/java/mekanism/common/util/RecipeUtils.java index 354ce1b1a..a0ba89c51 100644 --- a/src/main/java/mekanism/common/util/RecipeUtils.java +++ b/src/main/java/mekanism/common/util/RecipeUtils.java @@ -23,6 +23,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.CraftingManager; import net.minecraft.item.crafting.IRecipe; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; import net.minecraftforge.oredict.OreDictionary; public class RecipeUtils @@ -263,4 +264,17 @@ public class RecipeUtils return false; } + + public static IRecipe getRecipeFromGrid(InventoryCrafting inv, World world) + { + for(IRecipe recipe : (List)CraftingManager.getInstance().getRecipeList()) + { + if(recipe.matches(inv, world)) + { + return recipe; + } + } + + return null; + } } diff --git a/src/main/resources/assets/mekanism/gui/GuiFormulaicAssemblicator.png b/src/main/resources/assets/mekanism/gui/GuiFormulaicAssemblicator.png new file mode 100644 index 0000000000000000000000000000000000000000..ccf63f296e3ebd3d9b565e6ed8c8ac3f9ebbe6fb GIT binary patch literal 6824 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mekanism/gui/GuiUpgradeManagement.png b/src/main/resources/assets/mekanism/gui/GuiUpgradeManagement.png index 35aee32c44af9b995e6e12081475d8fcf8cc89da..3a899bdfa9497ae34a9d88f3b20509847cdac538 100644 GIT binary patch delta 1067 zcmV+`1l0S0DV-^hBYy-9X+uL$Nkc;*P;zf(X>4Tx062|}Rb6NtRTMtEb7vzY&QokO zg>Hg1+lHrgWSWcKdPn90sKGrRqvPeo9CG3uKX#J{(IASm?@ z+di}}l?o-=)F3E6wD^Ni=!>T7nL9I?X}YoAW$t|Qo$sD|?ti&w?*-_&s#unh6af~R zt}Pcb;&X?Oh&?NigomIP2BB9`9V=a_OaeAf3wO0!-$TNCU)j~&{-3S4MjaI(aUWu{ z=BNvZj{)$fRm*k(dis$cKk8Z@_G0L_F+jvGdbr_Z*TZu@evN5nWtO z;Zej(s*;~Z{0QP}ZGE;J;MNT3ndwE3s`n-8a z_I+}nIqm6u=<|e@EeHIimz0AQ#Dj=`p+-UW=i>gc+)5Aw8EP8kNq;VqqYhgy<6Uj0 z=+8?G7dO-&OBU<;fl{FVM6-)>fUj8wt5J-NPueZH>g)MY#m*OepL~TjtAT&M4YLUa zD3~yZy?+W#SOXDcC_o0^7T9R1gAN8V6s;5)ieI5-7aQlmJn}lUna#nz!j%5V$X|o` zxX!dHWQRV27P1=rj;t2bW$~+pTw@bIek?ZvKPDL<64`^#UNTAck#RBsB6*5DP4<%< zvJ+(Q`q)ZrMP58N*8RMUGg79TMcp~HyP#nIGk+>fTvOMqEDpAYBg-lK1zo-T#$T~q z=`1%wHmU-|3&GWIL{YNX(Qxa>rWCyRuBf>}*(bcU2l~2ICg+(V4}G z#U1l;@#I$zMt+vbndh(cT|8NDE)GVlmj(K2`BoWDjYO>UgY<{AEWIavDE-F0&3(#! z&3}E)eZgG6#@QDHLj zCkzNR&Px>zCja= zBtvA3lr~iNxL5O`B9%|&QfUxVJ5v*>v47M-4~Mg+cA#wn`}`f%scy1T>e6H0eF9n2 zI&SL?%@ub`(vxBuuQn={n(F9?s2GOGOpa(%huUpg8wKy)^pEtLGP@5GTP{bO`wYOo zKk@AQF5-@~0G1qpfyX0m7|+TF-UT@Ggxa#(!5xuEd<)>z_w4q+`Z9Qa{nY8)#2<64 l=PiJ>H#?ob-|uwRK0yDg0B4PV0id6JRZw95Z?hc)V-R=-8n*xd delta 1038 zcmV+p1o8WwDS#=EBYy+%X+uL$Nkc;*P;zf(X>4Tx062|}Ro!pfR1`mnZ(O7nKcKOW z4i$^9Ra0BJ8yc;~21%2p=|UR0&DbiW$#rfTQ`a`O(`{9s_5yDV_yd5l2Of}kLK+Oj z_Ok5(v`JGz71bo9J#^YYXp{DWs&KBaQ@dTpxRI}aIp=pi?|;!XK*v{_pO}_ARv`(`K_~P;r>1*Ox?C;-F2;pN*27;R!QM9q+Ux&wbylgT10KeMtdQo=mnqksdx=&F5&oys0TJd`E>GI|#kK((J)n0eU)DVBJ zYq?3pFC)I@_!%aD74f~sTqTWoFF^8{ntPr?L_-if$s_=TxZzG%&qCb(^K zdCoqnhMa4x{ z6hi)zV+ON`xsmg3L#>3I8=9NTb3f!hwJM>{)UK+QWxX9ld>D=;G@xL^4DLEuumLit zkcSMu9e;39Qv(A`lu*=Clo*MpVGd>OdF6n^am1Jntk;<}MrqIC5$=Q>n{*R}?8oOI zDUw5En2dl--Xw34!z7E+5pr%d2c?H4INKjdmEV*< zl@;X+<-BrtTbJ8*N%&OwR`^l)PWWE<8D!y-a9Q|CxFUQbT#TL7ym&1JoWQ-+)%LMCuYy_wP6ZWs zL5D3kvu*xEYtl=GNMYO54zpQqF~pph71JP#d&LoPNE~Olm7ll=btAavwoIM=mAd9q7A z>MqdgAh7QszoH+g!S^k(^Lixn-v&7J7v5PnBH45U;A;<{`?W~chj-$$p8;Grpf}uw z@Xk*pegW`m`}gsGT^YQaZZ(?^@V@H!1YqOiX7iurW^?09^uGph$@~{t0C9K{wF2RW IvpNK05K89@W&i*H diff --git a/src/main/resources/assets/mekanism/lang/en_US.lang b/src/main/resources/assets/mekanism/lang/en_US.lang index 4182d402e..e517a08c0 100644 --- a/src/main/resources/assets/mekanism/lang/en_US.lang +++ b/src/main/resources/assets/mekanism/lang/en_US.lang @@ -151,6 +151,7 @@ tile.MachineBlock3.QuantumEntangloporter.name=Quantum Entangloporter tile.MachineBlock3.SolarNeutronActivator.name=Solar Neutron Activator tile.MachineBlock3.Oredictionificator.name=Oredictionificator tile.MachineBlock3.ResistiveHeater.name=Resistive Heater +tile.MachineBlock3.FormulaicAssemblicator.name=Formulaic Assemblicator //Plastic tile.PlasticBlock.name=Plastic Block