aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines
diff options
context:
space:
mode:
authorRaven Szewczyk <git@eigenraven.me>2024-05-24 19:50:35 +0100
committerRaven Szewczyk <git@eigenraven.me>2024-05-24 19:50:35 +0100
commit6d1b2216464d4dad449ac6fcfec476832224a55e (patch)
tree526a0c15f7056313c80e6c0386e025e9b3f61781 /src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines
parentb5d35f40afa606ed1b07061dad82e0521a59c186 (diff)
downloadGT5-Unofficial-6d1b2216464d4dad449ac6fcfec476832224a55e.tar.gz
GT5-Unofficial-6d1b2216464d4dad449ac6fcfec476832224a55e.tar.bz2
GT5-Unofficial-6d1b2216464d4dad449ac6fcfec476832224a55e.zip
Merge addon sources
Diffstat (limited to 'src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines')
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_CropHarvestor.java716
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GregtechMetaAtmosphericReconditioner.java893
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GregtechMetaPollutionCreator.java458
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GregtechMetaPollutionDetector.java502
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GregtechMetaTileEntity_AutoChisel.java190
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GregtechMetaWirelessCharger.java672
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/misc/GMTE_AmazonPackager.java168
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialAlloySmelter.java223
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialArcFurnace.java337
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialCentrifuge.java228
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialChisel.java342
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialCokeOven.java209
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialCuttingMachine.java230
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialDehydrator.java250
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialElectrolyzer.java169
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialExtruder.java194
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialFluidHeater.java204
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialForgeHammer.java244
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialMacerator.java458
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialMixer.java213
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialMolecularTransformer.java241
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialMultiMachine.java514
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialPlatePress.java218
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialSifter.java209
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialThermalCentrifuge.java184
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialVacuumFreezer.java261
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialWashPlant.java372
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialWireMill.java215
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IsaMill.java529
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_NuclearSaltProcessingPlant.java224
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_SpargeTower.java507
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_DistillationTower.java491
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_EBF.java333
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_Fusion_MK4.java200
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_Fusion_MK5.java200
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_HeatExchanger.java414
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_Implosion.java177
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/steam/GregtechMetaTileEntity_SteamCompressor.java156
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/steam/GregtechMetaTileEntity_SteamMacerator.java165
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GT4Entity_AutoCrafter.java196
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GT4Entity_ThermalBoiler.java353
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMTE_ElementalDuplicator.java352
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMTE_FrothFlotationCell.java287
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMTE_NuclearReactor.java524
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntityTreeFarm.java809
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_AlloyBlastSmelter.java235
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_Cyclotron.java331
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_IndustrialFishingPond.java489
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_IndustrialRockBreaker.java367
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_LargeRocketEngine.java524
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_LargeSemifluidGenerator.java332
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_MassFabricator.java337
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_QuantumForceTransformer.java939
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_Refinery.java220
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_SolarTower.java675
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/algae/GregtechMTE_AlgaePondBase.java376
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/chemplant/GregtechMTE_ChemicalPlant.java676
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/mega/GregTechMetaTileEntity_MegaAlloyBlastSmelter.java468
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GT_MTE_LargeTurbine_Gas.java208
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GT_MTE_LargeTurbine_Plasma.java314
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GT_MTE_LargeTurbine_SCSteam.java126
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GT_MTE_LargeTurbine_SHSteam.java204
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GT_MTE_LargeTurbine_Steam.java215
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GregtechMetaTileEntity_LargerTurbineBase.java893
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/storage/GregtechMetaTileEntity_PowerSubStationController.java939
65 files changed, 23899 insertions, 0 deletions
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_CropHarvestor.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_CropHarvestor.java
new file mode 100644
index 0000000000..c592a68a40
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_CropHarvestor.java
@@ -0,0 +1,716 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.basic;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import org.apache.commons.lang3.ArrayUtils;
+
+import com.gtnewhorizon.gtnhlib.util.map.ItemStackMap;
+import com.gtnewhorizons.modularui.api.screen.ModularWindow;
+import com.gtnewhorizons.modularui.api.screen.UIBuildContext;
+import com.gtnewhorizons.modularui.common.widget.CycleButtonWidget;
+import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget;
+import com.gtnewhorizons.modularui.common.widget.ProgressBar;
+import com.gtnewhorizons.modularui.common.widget.SlotGroup;
+
+import gregtech.api.enums.GT_Values;
+import gregtech.api.enums.Textures;
+import gregtech.api.gui.modularui.GT_UIInfos;
+import gregtech.api.gui.modularui.GT_UITextures;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.metatileentity.MetaTileEntity;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicTank;
+import gregtech.api.objects.GT_ItemStack;
+import gregtech.api.objects.GT_RenderedTexture;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.api.objects.Logger;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.math.MathUtils;
+import gtPlusPlus.core.util.minecraft.ItemUtils;
+import gtPlusPlus.xmod.gregtech.api.gui.GTPP_UITextures;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+import ic2.api.crops.CropCard;
+import ic2.api.crops.ICropTile;
+import ic2.core.item.DamageHandler;
+
+public class GT_MetaTileEntity_CropHarvestor extends GT_MetaTileEntity_BasicTank {
+
+ private static final int SLOT_WEEDEX_1 = 1;
+ private static final int SLOT_WEEDEX_2 = 2;
+ private static final int SLOT_FERT_1 = 3;
+ private static final int SLOT_FERT_4 = 6;
+ private static final int SLOT_OUTPUT_START = 7;
+
+ public boolean mModeAlternative = false;
+ public boolean mHarvestEnabled = true;
+
+ public GT_MetaTileEntity_CropHarvestor(final int aID, final int aTier, final String aDescription) {
+ super(
+ aID,
+ "basicmachine.cropharvester.0" + aTier,
+ "Crop Manager (" + GT_Values.VN[aTier] + ")",
+ aTier,
+ 21,
+ aDescription);
+ }
+
+ public GT_MetaTileEntity_CropHarvestor(final String aName, final int aTier, final String[] aDescription,
+ final ITexture[][][] aTextures) {
+ super(aName, aTier, 21, aDescription, aTextures);
+ }
+
+ @Override
+ public boolean isTransformerUpgradable() {
+ return true;
+ }
+
+ @Override
+ public boolean isOverclockerUpgradable() {
+ return true;
+ }
+
+ @Override
+ public boolean isSimpleMachine() {
+ return true;
+ }
+
+ @Override
+ public boolean isAccessAllowed(EntityPlayer aPlayer) {
+ return true;
+ }
+
+ @Override
+ public boolean isInputFacing(ForgeDirection side) {
+ return true;
+ }
+
+ @Override
+ public boolean isEnetInput() {
+ return true;
+ }
+
+ @Override
+ public boolean isElectric() {
+ return true;
+ }
+
+ @Override
+ public long maxAmperesIn() {
+ return 8;
+ }
+
+ @Override
+ public long getMinimumStoredEU() {
+ return GT_Values.V[this.mTier];
+ }
+
+ @Override
+ public long maxEUStore() {
+ return GT_Values.V[this.mTier] * (this.mTier * GT_Values.V[this.mTier]);
+ }
+
+ @Override
+ public long maxEUInput() {
+ return GT_Values.V[this.mTier];
+ }
+
+ @Override
+ public int getCapacity() {
+ return 32000 * this.mTier;
+ }
+
+ @Override
+ public int getTankPressure() {
+ return -100;
+ }
+
+ @Override
+ public boolean onRightclick(final IGregTechTileEntity aBaseMetaTileEntity, final EntityPlayer aPlayer) {
+ GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer);
+ return true;
+ }
+
+ @Override
+ public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GT_MetaTileEntity_CropHarvestor(this.mName, this.mTier, this.mDescriptionArray, this.mTextures);
+ }
+
+ @Override
+ public int getSizeInventory() {
+ return 21;
+ }
+
+ private static int getRange(int aTier) {
+ return switch (aTier) {
+ case 1 -> 1;
+ case 2 -> 5;
+ case 3 -> 9;
+ case 4 -> 13;
+ case 5 -> 17;
+ case 6 -> 21;
+ case 7 -> 25;
+ case 8 -> 29;
+ case 9 -> 33;
+ default -> 0;
+ };
+ }
+
+ private HashSet<ICropTile> mCropCache = new HashSet<>();
+ private boolean mInvalidCache = false;
+
+ public boolean doesInventoryHaveSpace() {
+ for (int i = SLOT_OUTPUT_START; i < this.getSizeInventory(); i++) {
+ if (this.mInventory[i] == null || this.mInventory[i].stackSize < 64) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public long powerUsage() {
+ return this.maxEUInput() / 8;
+ }
+
+ public long powerUsageSecondary() {
+ return this.maxEUInput() / 32;
+ }
+
+ @Override
+ public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {
+ super.onPostTick(aBaseMetaTileEntity, aTick);
+ if (!getBaseMetaTileEntity().isServerSide() || !getBaseMetaTileEntity().isAllowedToWork()
+ || (!getBaseMetaTileEntity().hasWorkJustBeenEnabled() && aTick % 100 != 0)) return;
+
+ if (this.getBaseMetaTileEntity()
+ .getUniversalEnergyStored() < getMinimumStoredEU()) return;
+
+ int aTileX = this.getBaseMetaTileEntity()
+ .getXCoord();
+ int aTileY = this.getBaseMetaTileEntity()
+ .getXCoord();
+ int aTileZ = this.getBaseMetaTileEntity()
+ .getXCoord();
+
+ int aRadius = 10 + getRange(this.mTier);
+ int aSide = (aRadius - 1) / 2;
+ Map<ItemStack, Integer> aAllDrops = new ItemStackMap<>(true);
+
+ if (this.mCropCache.isEmpty() || aTick % 1200 == 0 || this.mInvalidCache) {
+ if (!this.mCropCache.isEmpty()) {
+ this.mCropCache.clear();
+ }
+ // Logger.INFO("Looking for crops.");
+ for (int y = -2; y <= 2; y++) {
+ for (int x = (-aSide); x <= aSide; x++) {
+ for (int z = (-aSide); z <= aSide; z++) {
+ TileEntity tTileEntity = getBaseMetaTileEntity().getTileEntityOffset(x, y, z);
+ if (tTileEntity != null && tTileEntity instanceof ICropTile tCrop) {
+ this.mCropCache.add(tCrop);
+ }
+ }
+ }
+ }
+ }
+
+ // Process Cache
+ if (!doesInventoryHaveSpace()) return;
+
+ for (ICropTile tCrop : this.mCropCache) {
+ if (tCrop == null) {
+ this.mInvalidCache = true;
+ break;
+ }
+ CropCard aCrop = tCrop.getCrop();
+ if (aCrop == null) continue;
+
+ if (this.mModeAlternative) processSecondaryFunctions(tCrop);
+ if (!this.mHarvestEnabled) continue;
+
+ if (aCrop.canBeHarvested(tCrop) && tCrop.getSize() == aCrop.getOptimalHavestSize(tCrop)) {
+ if (!getBaseMetaTileEntity().decreaseStoredEnergyUnits(powerUsage(), true)) continue;
+ ItemStack[] aHarvest = tCrop.harvest_automated(true);
+ if (aHarvest == null) continue;
+
+ for (ItemStack aStack : aHarvest) {
+ if (!ItemUtils.checkForInvalidItems(aStack)) continue;
+ if (this.mTier * 5 > MathUtils.randInt(1, 100)) {
+ aStack.stackSize += Math.floor(tCrop.getGain() / 10);
+ Logger.INFO("Bonus output given for " + aCrop.displayName());
+ }
+ Logger.INFO("Harvested " + aCrop.displayName());
+ aAllDrops.merge(aStack, aStack.stackSize, Integer::sum);
+ }
+ }
+ }
+
+ if (aAllDrops.isEmpty()) return;
+
+ Logger.INFO("Handling " + aAllDrops.size() + " Harvests");
+ for (int i = SLOT_OUTPUT_START; i < this.getSizeInventory() && !aAllDrops.isEmpty(); i++) {
+ ItemStack invStack = mInventory[i];
+ if (invStack == null || GT_Utility.isStackInvalid(invStack) || invStack.stackSize == 0) {
+ Iterator<Entry<ItemStack, Integer>> iter = aAllDrops.entrySet()
+ .iterator();
+ if (!iter.hasNext()) return;
+ Entry<ItemStack, Integer> e = iter.next();
+ int toAdd = e.getValue();
+ int toAddThisSlot = Math.min(
+ toAdd,
+ e.getKey()
+ .getMaxStackSize());
+ getBaseMetaTileEntity().setInventorySlotContents(i, GT_Utility.copyAmount(toAddThisSlot, e.getKey()));
+ toAdd -= toAddThisSlot;
+ if (toAdd <= toAddThisSlot) {
+ iter.remove();
+ } else {
+ e.setValue(toAdd);
+ }
+ } else {
+ Integer toAddMaybeNull = aAllDrops.get(invStack);
+ if (toAddMaybeNull != null) {
+ int toAdd = toAddMaybeNull;
+ int space = Math.min(invStack.getMaxStackSize(), getInventoryStackLimit()) - invStack.stackSize;
+ if (toAdd <= space) {
+ getBaseMetaTileEntity().addStackToSlot(i, invStack, toAdd);
+ aAllDrops.remove(invStack);
+ } else {
+ getBaseMetaTileEntity().addStackToSlot(i, invStack, space);
+ aAllDrops.put(invStack, toAdd - space);
+ }
+ }
+ }
+ }
+ }
+
+ public boolean hasFertilizer() {
+ for (int i = SLOT_FERT_1; i <= SLOT_FERT_4; i++) {
+ if (this.mInventory[i] != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean consumeFertilizer(boolean aSimulate) {
+ if (hasFertilizer()) {
+ for (int i = SLOT_FERT_1; i <= SLOT_FERT_4; i++) {
+ if (this.mInventory[i] != null) {
+ consume(i, 1, aSimulate);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean hasWeedEX() {
+ for (int i = SLOT_WEEDEX_1; i <= SLOT_WEEDEX_2; i++) {
+ if (this.mInventory[i] != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean consumeWeedEX(boolean aSimulate) {
+ if (hasWeedEX()) {
+ for (int i = SLOT_WEEDEX_1; i <= SLOT_WEEDEX_2; i++) {
+ if (this.mInventory[i] != null) {
+ damage(i, 1, aSimulate);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public void processSecondaryFunctions(ICropTile aCrop) {
+ if (!this.mModeAlternative) {
+ return;
+ }
+ if (hasFertilizer() && consumeFertilizer(true)
+ && this.getBaseMetaTileEntity()
+ .getUniversalEnergyStored() >= getMinimumStoredEU()
+ && getBaseMetaTileEntity().decreaseStoredEnergyUnits(powerUsageSecondary(), true)
+ && applyFertilizer(aCrop)) {
+ if (consumeFertilizer(false)) {
+ // Logger.INFO("Consumed Fert.");
+ }
+ }
+ if (this.getFluidAmount() > 0 && this.getBaseMetaTileEntity()
+ .getUniversalEnergyStored() >= getMinimumStoredEU()
+ && getBaseMetaTileEntity().decreaseStoredEnergyUnits(powerUsageSecondary(), true)
+ && applyHydration(aCrop)) {
+ // Logger.INFO("Consumed Water.");
+ }
+ if (hasWeedEX() && consumeWeedEX(true)
+ && this.getBaseMetaTileEntity()
+ .getUniversalEnergyStored() >= getMinimumStoredEU()
+ && getBaseMetaTileEntity().decreaseStoredEnergyUnits(powerUsageSecondary(), true)
+ && applyWeedEx(aCrop)) {
+ if (consumeWeedEX(false)) {
+ // Logger.INFO("Consumed Weed-EX.");
+ }
+ }
+ }
+
+ public boolean applyWeedEx(ICropTile aCrop) {
+ if (aCrop.getWeedExStorage() < 150) {
+ aCrop.setWeedExStorage(aCrop.getWeedExStorage() + 50);
+ boolean triggerDecline;
+ triggerDecline = aCrop.getWorld().rand.nextInt(3) == 0;
+ if (aCrop.getCrop() != null && aCrop.getCrop()
+ .isWeed(aCrop) && aCrop.getWeedExStorage() >= 75 && triggerDecline) {
+ switch (aCrop.getWorld().rand.nextInt(5)) {
+ case 0:
+ if (aCrop.getGrowth() > 0) {
+ aCrop.setGrowth((byte) (aCrop.getGrowth() - 1));
+ }
+ case 1:
+ if (aCrop.getGain() > 0) {
+ aCrop.setGain((byte) (aCrop.getGain() - 1));
+ }
+ default:
+ if (aCrop.getResistance() > 0) {
+ aCrop.setResistance((byte) (aCrop.getResistance() - 1));
+ }
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public boolean applyFertilizer(ICropTile aCrop) {
+ if (aCrop.getNutrientStorage() >= 100) {
+ return false;
+ } else {
+ // Logger.INFO("Current Nutrient: "+aCrop.getNutrientStorage()+" for "+aCrop.getCrop().displayName());
+ aCrop.setNutrientStorage(aCrop.getNutrientStorage() + 100);
+ return true;
+ }
+ }
+
+ public boolean applyHydration(ICropTile aCrop) {
+ if (aCrop.getHydrationStorage() >= 200 || this.getFluidAmount() == 0) {
+ // Logger.INFO("Hydration Max");
+ return false;
+ } else {
+ int apply = 200 - aCrop.getHydrationStorage();
+ if (this.getFluidAmount() >= 0) {
+ int drain = 0;
+ if (this.getFluidAmount() >= apply) {
+ drain = apply;
+ } else {
+ drain = this.getFluidAmount();
+ }
+ this.mFluid.amount -= drain;
+ if (this.mFluid.amount <= 0) {
+ this.mFluid = null;
+ }
+ // Logger.INFO("Did Hydrate");
+ aCrop.setHydrationStorage(aCrop.getHydrationStorage() + drain);
+ return true;
+ } else {
+ // Logger.INFO("No water?");
+ return false;
+ }
+ }
+ }
+
+ public boolean consume(int aSlot, int amount, boolean simulate) {
+ ItemStack stack = this.mInventory[aSlot];
+ if (stack != null && stack.stackSize >= amount) {
+ int currentAmount = Math.min(amount, stack.stackSize);
+ amount -= currentAmount;
+ if (!simulate) {
+ if (stack.stackSize == currentAmount) {
+ this.mInventory[aSlot] = null;
+ } else {
+ stack.stackSize -= currentAmount;
+ }
+ } else {
+ return amount >= 0;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public ItemStack damage(int aSlot, int amount, boolean simulate) {
+ ItemStack ret = null;
+ int damageApplied = 0;
+ ItemStack stack = this.mInventory[aSlot];
+ Item item = stack.getItem();
+ if (stack != null && item.isDamageable()
+ && (ret == null || stack.getItem() == ret.getItem() && ItemStack.areItemStackTagsEqual(stack, ret))) {
+ if (simulate) {
+ stack = stack.copy();
+ }
+ int maxDamage = DamageHandler.getMaxDamage(stack);
+ while (amount > 0 && stack.stackSize > 0) {
+ int currentAmount = Math.min(amount, maxDamage - DamageHandler.getDamage(stack));
+ DamageHandler.damage(stack, currentAmount, null);
+ damageApplied += currentAmount;
+ amount -= currentAmount;
+ if (DamageHandler.getDamage(stack) >= maxDamage) {
+ --stack.stackSize;
+ DamageHandler.setDamage(stack, 0);
+ }
+
+ if (ret == null) {
+ ret = stack.copy();
+ }
+ }
+ if (stack.stackSize == 0 && !simulate) {
+ this.mInventory[aSlot] = null;
+ }
+ }
+
+ if (ret != null) {
+ int i = DamageHandler.getMaxDamage(ret);
+ ret.stackSize = damageApplied / i;
+ DamageHandler.setDamage(ret, damageApplied % i);
+ }
+ return ret;
+ }
+
+ @Override
+ public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side,
+ ItemStack aStack) {
+ return aStack != null && aIndex >= SLOT_OUTPUT_START && aIndex < this.getSizeInventory();
+ }
+
+ @Override
+ public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side,
+ ItemStack aStack) {
+ if (aStack != null) {
+ if (aStack.getItem()
+ .getUnlocalizedName()
+ .equals("ic2.itemFertilizer")) {
+ return aIndex >= SLOT_FERT_1 && aIndex <= SLOT_FERT_4;
+ } else if (aStack.getItem()
+ .getUnlocalizedName()
+ .equals("ic2.itemWeedEx")) {
+ return aIndex >= SLOT_WEEDEX_1 && aIndex <= SLOT_WEEDEX_2;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String[] getDescription() {
+ int aRadius = 10 + getRange(this.mTier);
+ int aSide = (aRadius - 1) / 2;
+ return ArrayUtils.addAll(
+ this.mDescriptionArray,
+ "Secondary mode can Hydrate/Fertilize/Weed-EX",
+ "Consumes " + powerUsage() + "eu per harvest",
+ "Consumes " + powerUsageSecondary() + "eu per secondary operation",
+ "Can harvest 1 block level above and below itself",
+ "Radius: " + aSide + " blocks each side (" + aRadius + "x3x" + aRadius + ")",
+ "Has " + (this.mTier * 5) + "% chance for extra drops",
+ "Holds " + this.getCapacity() + "L of Water",
+ CORE.GT_Tooltip.get());
+ }
+
+ @Override
+ public boolean allowCoverOnSide(ForgeDirection side, GT_ItemStack aStack) {
+ return true;
+ }
+
+ /*
+ * @Override public int getTextureIndex(byte aSide, byte aFacing, boolean aActive, boolean aRedstone) { if (aSide ==
+ * aFacing) return 118+(aRedstone?8:0); if (GT_Utility.getOppositeSide(aSide) == aFacing) return
+ * 113+(aRedstone?8:0); int tIndex = 128+(aRedstone?8:0); switch (aFacing) { case 0: return tIndex+64; case 1:
+ * return tIndex+32; case 2: switch (aSide) { case 0: return tIndex+32; case 1: return tIndex+32; case 4: return
+ * tIndex+16; case 5: return tIndex+48; } case 3: switch (aSide) { case 0: return tIndex+64; case 1: return
+ * tIndex+64; case 4: return tIndex+48; case 5: return tIndex+16; } case 4: switch (aSide) { case 0: return
+ * tIndex+16; case 1: return tIndex+16; case 2: return tIndex+48; case 3: return tIndex+16; } case 5: switch (aSide)
+ * { case 0: return tIndex+48; case 1: return tIndex+48; case 2: return tIndex+16; case 3: return tIndex+48; } }
+ * return tIndex; }
+ */
+
+ @Override
+ public ITexture[][][] getTextureSet(final ITexture[] aTextures) {
+ final ITexture[][][] rTextures = new ITexture[10][17][];
+ for (byte i = -1; i < 16; i++) {
+ rTextures[0][i + 1] = this.getFront(i);
+ rTextures[1][i + 1] = this.getBack(i);
+ rTextures[2][i + 1] = this.getBottom(i);
+ rTextures[3][i + 1] = this.getTop(i);
+ rTextures[4][i + 1] = this.getSides(i);
+ rTextures[5][i + 1] = this.getFront(i);
+ rTextures[6][i + 1] = this.getBack(i);
+ rTextures[7][i + 1] = this.getBottom(i);
+ rTextures[8][i + 1] = this.getTop(i);
+ rTextures[9][i + 1] = this.getSides(i);
+ }
+ return rTextures;
+ }
+
+ @Override
+ public ITexture[] getTexture(final IGregTechTileEntity aBaseMetaTileEntity, final ForgeDirection side,
+ final ForgeDirection facing, final int aColorIndex, final boolean aActive, final boolean aRedstone) {
+ if (side == ForgeDirection.DOWN || side == ForgeDirection.UP) {
+ return this.mTextures[3][aColorIndex + 1];
+ } else {
+ return this.mTextures[4][aColorIndex + 1];
+ }
+ /*
+ * return this.mTextures[(aActive ? 5 : 0) + (side == facing ? 0 : aSide == GT_Utility.getOppositeSide(aFacing)
+ * ? 1 : side == ForgeDirection.DOWN ? 2 : side == ForgeDirection.UP ? 3 : 4)][aColorIndex + 1];
+ */
+ }
+
+ public ITexture[] getFront(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_CropHarvester_Cutter) };
+ }
+
+ public ITexture[] getBack(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_CropHarvester_Cutter) };
+ }
+
+ public ITexture[] getBottom(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_CropHarvester_Boxes) };
+ }
+
+ public ITexture[] getTop(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_CropHarvester_Boxes) };
+ }
+
+ public ITexture[] getSides(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_CropHarvester_Cutter) };
+ }
+
+ @Override
+ public boolean doesFillContainers() {
+ return false;
+ }
+
+ @Override
+ public boolean doesEmptyContainers() {
+ return false;
+ }
+
+ @Override
+ public boolean canTankBeFilled() {
+ return true;
+ }
+
+ @Override
+ public boolean canTankBeEmptied() {
+ return false;
+ }
+
+ @Override
+ public boolean displaysItemStack() {
+ return false;
+ }
+
+ @Override
+ public boolean displaysStackSize() {
+ return false;
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ super.saveNBTData(aNBT);
+ aNBT.setBoolean("mModeAlternative", this.mModeAlternative);
+ aNBT.setBoolean("mHarvestEnabled", this.mHarvestEnabled);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ this.mModeAlternative = aNBT.getBoolean("mModeAlternative");
+ if (aNBT.hasKey("mHarvestEnabled")) {
+ this.mHarvestEnabled = aNBT.getBoolean("mHarvestEnabled");
+ }
+ }
+
+ @Override
+ public boolean useModularUI() {
+ return true;
+ }
+
+ @Override
+ public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) {
+ builder.widget(
+ new CycleButtonWidget().setToggle(() -> mModeAlternative, val -> mModeAlternative = val)
+ .setTexture(GTPP_UITextures.OVERLAY_BUTTON_HARVESTER_MODE)
+ .addTooltip(0, "Enable Hydration/Fertilizing/Weed-EX")
+ .addTooltip(1, "Disable Hydration/Fertilizing/Weed-EX")
+ .setBackground(GT_UITextures.BUTTON_STANDARD)
+ .setPos(47, 63)
+ .setSize(18, 18));
+ builder.widget(
+ new CycleButtonWidget().setToggle(() -> mHarvestEnabled, val -> mHarvestEnabled = val)
+ .setTexture(GTPP_UITextures.OVERLAY_BUTTON_HARVESTER_TOGGLE)
+ .addTooltip(0, "Enable Harvest")
+ .addTooltip(1, "Disable Harvest")
+ .setBackground(GT_UITextures.BUTTON_STANDARD)
+ .setPos(67, 63)
+ .setSize(18, 18));
+ builder.widget(
+ SlotGroup.ofItemHandler(inventoryHandler, 2)
+ .startFromSlot(SLOT_WEEDEX_1)
+ .endAtSlot(SLOT_WEEDEX_2)
+ .applyForWidget(
+ widget -> widget.setFilter(
+ stack -> stack != null && stack.getItem()
+ .getUnlocalizedName()
+ .equals("ic2.itemWeedEx"))
+ .setBackground(getGUITextureSet().getItemSlot(), GTPP_UITextures.OVERLAY_SLOT_WEED_EX))
+ .build()
+ .setPos(7, 13))
+ .widget(
+ SlotGroup.ofItemHandler(inventoryHandler, 2)
+ .startFromSlot(SLOT_FERT_1)
+ .endAtSlot(SLOT_FERT_4)
+ .applyForWidget(
+ widget -> widget.setFilter(
+ stack -> stack != null && stack.getItem()
+ .getUnlocalizedName()
+ .equals("ic2.itemFertilizer"))
+ .setBackground(getGUITextureSet().getItemSlot(), GTPP_UITextures.OVERLAY_SLOT_FERTILIZER))
+ .build()
+ .setPos(7, 31))
+ .widget(
+ SlotGroup.ofItemHandler(inventoryHandler, 6)
+ .startFromSlot(SLOT_OUTPUT_START)
+ .endAtSlot(SLOT_OUTPUT_START + 6 * 3)
+ .canInsert(false)
+ .build()
+ .setPos(61, 7));
+ builder
+ .widget(
+ new ProgressBar()
+ .setTexture(GTPP_UITextures.PROGRESSBAR_BOILER_EMPTY, GT_UITextures.PROGRESSBAR_BOILER_WATER, 54)
+ .setDirection(ProgressBar.Direction.UP)
+ .setProgress(() -> (float) getFluidAmount() / getCapacity())
+ .setSynced(false, false)
+ .dynamicTooltip(
+ () -> Collections.singletonList("Water: " + getFluidAmount() + "L / " + getCapacity() + "L"))
+ .setPos(47, 7)
+ .setSize(10, 54))
+ .widget(new FakeSyncWidget.FluidStackSyncer(this::getDrainableStack, this::setDrainableStack));
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GregtechMetaAtmosphericReconditioner.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GregtechMetaAtmosphericReconditioner.java
new file mode 100644
index 0000000000..9f2789b520
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GregtechMetaAtmosphericReconditioner.java
@@ -0,0 +1,893 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.basic;
+
+import static gregtech.api.enums.GT_Values.V;
+
+import java.util.Collections;
+
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.world.World;
+import net.minecraft.world.chunk.Chunk;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import org.apache.commons.lang3.ArrayUtils;
+
+import com.gtnewhorizons.modularui.api.screen.ModularWindow;
+import com.gtnewhorizons.modularui.api.screen.UIBuildContext;
+import com.gtnewhorizons.modularui.common.widget.DrawableWidget;
+import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget;
+import com.gtnewhorizons.modularui.common.widget.SlotWidget;
+
+import gregtech.api.enums.Materials;
+import gregtech.api.enums.SoundResource;
+import gregtech.api.enums.Textures;
+import gregtech.api.gui.modularui.GT_UITextures;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.items.GT_MetaGenerated_Tool;
+import gregtech.api.metatileentity.MetaTileEntity;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine;
+import gregtech.api.objects.GT_ItemStack;
+import gregtech.api.objects.GT_RenderedTexture;
+import gregtech.api.util.GT_ModHandler;
+import gregtech.api.util.GT_Utility;
+import gregtech.common.items.GT_MetaGenerated_Tool_01;
+import gtPlusPlus.api.objects.Logger;
+import gtPlusPlus.api.objects.data.AutoMap;
+import gtPlusPlus.core.item.general.ItemAirFilter;
+import gtPlusPlus.core.item.general.ItemBasicScrubberTurbine;
+import gtPlusPlus.core.recipe.common.CI;
+import gtPlusPlus.core.util.math.MathUtils;
+import gtPlusPlus.core.util.minecraft.gregtech.PollutionUtils;
+import gtPlusPlus.xmod.gregtech.api.gui.GTPP_UITextures;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaAtmosphericReconditioner extends GT_MetaTileEntity_BasicMachine {
+
+ public int mPollutionReduction = 0;
+ protected int mBaseEff = 2500;
+ protected int mOptimalAirFlow = 0;
+ protected boolean mHasPollution = false;
+ protected int SLOT_ROTOR = 5;
+ protected int SLOT_FILTER = 6;
+ protected static boolean mPollutionEnabled = true;
+
+ protected boolean mSaveRotor = false;
+
+ public GregtechMetaAtmosphericReconditioner(int aID, String aName, String aNameRegional, int aTier) {
+ super(
+ aID,
+ aName,
+ aNameRegional,
+ aTier,
+ 2,
+ "Making sure you don't live in Gwalior - Uses 2A",
+ 3,
+ 0,
+ new ITexture[] { new GT_RenderedTexture(Textures.BlockIcons.OVERLAY_SIDE_MASSFAB_ACTIVE),
+ new GT_RenderedTexture(Textures.BlockIcons.OVERLAY_SIDE_MASSFAB),
+ new GT_RenderedTexture(TexturesGtBlock.Overlay_MatterFab_Active),
+ new GT_RenderedTexture(TexturesGtBlock.Overlay_MatterFab),
+ new GT_RenderedTexture(TexturesGtBlock.Overlay_Machine_Vent_Fast),
+ new GT_RenderedTexture(TexturesGtBlock.Overlay_Machine_Vent),
+ new GT_RenderedTexture(Textures.BlockIcons.OVERLAY_BOTTOM_MASSFAB_ACTIVE),
+ new GT_RenderedTexture(Textures.BlockIcons.OVERLAY_BOTTOM_MASSFAB) });
+ mPollutionEnabled = PollutionUtils.isPollutionEnabled();
+ }
+
+ public GregtechMetaAtmosphericReconditioner(String aName, int aTier, String[] aDescription,
+ ITexture[][][] aTextures) {
+ super(aName, aTier, 2, aDescription, aTextures, 2, 0);
+ mPollutionEnabled = PollutionUtils.isPollutionEnabled();
+ }
+
+ @Override
+ public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaAtmosphericReconditioner(this.mName, this.mTier, this.mDescriptionArray, this.mTextures);
+ }
+
+ @Override
+ public String[] getDescription() {
+
+ boolean highTier = this.mTier >= 7;
+
+ String[] A = ArrayUtils.addAll(
+ this.mDescriptionArray,
+ highTier ? "Will attempt to remove 1/4 pollution from 8 surrounding chunks" : "",
+ highTier ? "If these chunks are not loaded, they will be ignored" : "",
+ "Requires a turbine rotor and an Air Filter [T1/T2] to run.",
+ "The turbine rotor must be manually inserted/replaced",
+ "Can be configured with a soldering iron to change modes",
+ "Low Efficiency: Removes half pollution, Turbine takes 50% dmg",
+ "High Efficiency: Removes full pollution, Turbine takes 100% dmg",
+ "Turbine Rotor will not break in LE mode",
+ "Insert an equal tier Conveyor Module to enable automation");
+ if (!mPollutionEnabled) {
+ String[] B = new String[] { "===============================================",
+ "Pollution is disabled, scrubbers will now have a bonus use",
+ "They are now able to remove ALL lingering pollution as GT ignores it", "and it will linger forever!",
+ "===============================================", };
+ A = ArrayUtils.addAll(A, B);
+ }
+ return A;
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ super.saveNBTData(aNBT);
+ aNBT.setInteger("mOptimalAirFlow", this.mOptimalAirFlow);
+ aNBT.setBoolean("mSaveRotor", mSaveRotor);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ this.mOptimalAirFlow = aNBT.getInteger("mOptimalAirFlow");
+ this.mSaveRotor = aNBT.getBoolean("mSaveRotor");
+ }
+
+ @Override
+ public long maxAmperesIn() {
+ return 2;
+ }
+
+ @Override
+ public long getMinimumStoredEU() {
+ return V[mTier] * 2;
+ }
+
+ @Override
+ public long maxEUStore() {
+ return V[mTier] * 256;
+ }
+
+ @Override
+ public long maxEUInput() {
+ return V[mTier];
+ }
+
+ @Override
+ public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {
+ super.onPostTick(aBaseMetaTileEntity, aTick);
+ if (aBaseMetaTileEntity.isServerSide()) {
+
+ // Get Current Pollution Amount.
+ int mCurrentPollution = getCurrentChunkPollution();
+ boolean isIdle = true;
+
+ // Get Inventory Item
+ ItemStack stackRotor = this.mInventory[SLOT_ROTOR];
+ ItemStack stackFilter = this.mInventory[SLOT_FILTER];
+
+ // Power Drain
+ long drainEU = maxEUInput() * maxAmperesIn();
+ if (aBaseMetaTileEntity.isActive() && aBaseMetaTileEntity.getStoredEU() >= drainEU) {
+ if (aBaseMetaTileEntity.decreaseStoredEnergyUnits(drainEU, false)) {
+ isIdle = false;
+ } else {
+ aBaseMetaTileEntity.setActive(false);
+ this.sendSound((byte) -122);
+ }
+ } else if (!aBaseMetaTileEntity.isActive() && aBaseMetaTileEntity.getStoredEU() >= drainEU / 4) {
+ if (aBaseMetaTileEntity.decreaseStoredEnergyUnits((drainEU / 4), false)) {
+ isIdle = false;
+ } else {
+ aBaseMetaTileEntity.setActive(false);
+ this.sendSound((byte) -122);
+ }
+ } else {
+ aBaseMetaTileEntity.setActive(false);
+ this.sendSound((byte) -122);
+ }
+
+ // Only try once/sec.
+ if (!isIdle && aTick % 20L == 0L) {
+
+ for (int i = 0; i < this.mInventory.length; i++) {
+ ItemStack aSlotContent = this.mInventory[i];
+ if (aSlotContent != null) {
+ Logger.INFO("Found " + aSlotContent.getDisplayName() + " in slot " + i);
+ }
+ }
+
+ for (int i = 0; i < this.mInventory.length; i++) {
+ if (hasRotor(this.mInventory[i])) {
+ Logger.INFO("Found Rotor in slot " + i);
+ break;
+ }
+ }
+ for (int i = 0; i < this.mInventory.length; i++) {
+ if (hasAirFilter(this.mInventory[i])) {
+ Logger.INFO("Found Filter in slot " + i);
+ break;
+ }
+ }
+
+ // Check if machine can work.
+ if ((aBaseMetaTileEntity.isAllowedToWork())) {
+ Logger.INFO("Can work.");
+
+ // Enable machine animation/graphic
+ if (hasRotor(stackRotor) && hasAirFilter(stackFilter) && this.mHasPollution) {
+ if (!this.getBaseMetaTileEntity()
+ .isActive()) {
+ Logger.INFO("Set Active.");
+ aBaseMetaTileEntity.setActive(true);
+ }
+ } else if (!this.mHasPollution || mCurrentPollution <= 0
+ || stackRotor == null
+ || stackFilter == null
+ || !hasRotor(stackRotor)
+ || !hasAirFilter(stackFilter)) {
+ if (!this.getBaseMetaTileEntity()
+ .isActive()) {
+ Logger.INFO("Set Inactive.");
+ aBaseMetaTileEntity.setActive(false);
+ this.sendSound((byte) -122);
+ }
+ }
+
+ // If Active.
+ if (aBaseMetaTileEntity.isActive()) {
+ Logger.INFO("Doing something.");
+
+ // Do nothing if there is no pollution.
+ if (this.mHasPollution && mCurrentPollution > 0) {
+ Logger
+ .INFO("Has Pollution? " + mHasPollution + ", Current Pollution: " + mCurrentPollution);
+
+ // Only check every 30s.
+ if (!isIdle && aTick % (20L * 30) == 0L) {
+ mPollutionEnabled = PollutionUtils.isPollutionEnabled();
+ // Clear out pollution if it's disabled, because I am a nice gal.
+ if (!PollutionUtils.isPollutionEnabled()) {
+ PollutionUtils.nullifyPollution(this.getBaseMetaTileEntity());
+ }
+ }
+
+ // Use a Turbine
+ if (hasRotor(stackRotor) && hasAirFilter(stackFilter)) {
+ Logger.INFO("Found Turbine.");
+
+ mBaseEff = getBaseEfficiency(stackRotor);
+ mOptimalAirFlow = getOptimalAirFlow(stackRotor);
+
+ // Make sure we have a valid Turbine and Eff/Airflow
+ if (this.mBaseEff > 0 && this.mOptimalAirFlow > 0) {
+ // Utils.LOG_WARNING("Pollution Cleaner [5]");
+
+ // Log Debug information.
+ Logger.INFO("mBaseEff[1]:" + mBaseEff);
+ Logger.INFO("mOptimalAirFlow[1]:" + mOptimalAirFlow);
+
+ // Calculate The Voltage we are running
+ long tVoltage = drainEU;
+ byte tTier = (byte) Math.max(1, GT_Utility.getTier(tVoltage));
+
+ // Check Sides for Air,
+ // More air means more pollution processing.
+ int mAirSides = getFreeSpaces();
+
+ int reduction = 0;
+
+ // If no sides are free, how will you process the atmosphere?
+ if (mAirSides > 0) {
+ reduction += (((Math.max((tTier - 2), 1) * 2) * 50) * mAirSides); // Was
+ // originally
+ // *100
+ Logger.INFO("mPollutionReduction[1]:" + reduction);
+
+ // I stole this code
+ reduction = (MathUtils.safeInt((long) reduction * this.mBaseEff) / 100000)
+ * mAirSides
+ * Math.max((tTier - 2), 1);
+ Logger.INFO("reduction[2]:" + reduction);
+ reduction = MathUtils.safeInt(((long) reduction / 100) * this.mOptimalAirFlow);
+ Logger.INFO("reduction[3]:" + reduction);
+
+ mPollutionReduction = reduction;
+
+ // Set a temp to remove variable to aleviate duplicate code.
+ int toRemove = 0;
+
+ Logger.INFO("mCurrentPollution[4]:" + mCurrentPollution);
+ Logger.INFO("mCurrentPollution[5]:" + reduction);
+ if (reduction <= mCurrentPollution) {
+ // Clean some Air.
+ toRemove = reduction;
+ } else {
+ // Makes sure we don't get negative pollution.
+ toRemove = mCurrentPollution;
+ }
+
+ toRemove = toRemove / 2;
+ Logger.INFO("mCurrentPollution[6]:" + toRemove);
+
+ // We are good to clean
+ if (toRemove > 0) {
+ if (damageTurbineRotor() && damageAirFilter()) {
+ Logger.INFO("Removing " + toRemove + " pollution");
+ removePollution(mSaveRotor ? (toRemove / 2) : toRemove);
+ Logger.INFO("mNewPollution[4]:" + getCurrentChunkPollution());
+ } else {
+ Logger.INFO("Could not damage turbine rotor or Air Filter.");
+ aBaseMetaTileEntity.setActive(false);
+ }
+ } // End of pollution removal block.
+ } // End of valid air sides block.
+ } // End of valid toolstats block.
+ } // End of correct inventory item block.
+ else {
+ // Utils.LOG_WARNING("Wrong Tool metaitem Found.");
+ }
+ }
+ } else if (!aBaseMetaTileEntity.isActive()) {
+ return;
+ }
+ } // End of can work block.
+ else { // Disable Machine.
+ // aBaseMetaTileEntity.setActive(false);
+ }
+ } // End of 1/sec action block.
+ else {
+
+ if (hasRotor(stackRotor) && hasAirFilter(stackFilter)
+ && this.mHasPollution
+ && !isIdle
+ && aBaseMetaTileEntity.isAllowedToWork()) {
+ aBaseMetaTileEntity.setActive(true);
+ } else if (isIdle || !this.mHasPollution
+ || mCurrentPollution <= 0
+ || stackRotor == null
+ || stackFilter == null
+ || !hasRotor(stackRotor)
+ || !hasAirFilter(stackFilter)) {
+ aBaseMetaTileEntity.setActive(false);
+ }
+ }
+ if (this.getBaseMetaTileEntity()
+ .isActive()) {
+ if (MathUtils.randInt(0, 5) <= 2) {
+ this.sendSound((byte) -120);
+ }
+ }
+ } // End of is serverside block.
+ }
+
+ public int getCurrentChunkPollution() {
+ int mCurrentChunkPollution = 0;
+ if (this.mTier < 7) {
+ mCurrentChunkPollution = PollutionUtils.getPollution(getBaseMetaTileEntity());
+ } else {
+ AutoMap<Chunk> aSurrounding = new AutoMap<>();
+ World aWorld = this.getBaseMetaTileEntity()
+ .getWorld();
+ int xPos = this.getBaseMetaTileEntity()
+ .getXCoord();
+ int zPos = this.getBaseMetaTileEntity()
+ .getZCoord();
+ Chunk a1 = aWorld.getChunkFromBlockCoords(xPos - 32, zPos - 32);
+ Chunk a2 = aWorld.getChunkFromBlockCoords(xPos - 32, zPos);
+ Chunk a3 = aWorld.getChunkFromBlockCoords(xPos - 32, zPos + 32);
+ Chunk b1 = aWorld.getChunkFromBlockCoords(xPos, zPos - 32);
+ Chunk b2 = aWorld.getChunkFromBlockCoords(xPos, zPos);
+ Chunk b3 = aWorld.getChunkFromBlockCoords(xPos, zPos + 32);
+ Chunk c1 = aWorld.getChunkFromBlockCoords(xPos + 32, zPos - 32);
+ Chunk c2 = aWorld.getChunkFromBlockCoords(xPos + 32, zPos);
+ Chunk c3 = aWorld.getChunkFromBlockCoords(xPos + 32, zPos + 32);
+ aSurrounding.put(a1);
+ aSurrounding.put(a2);
+ aSurrounding.put(a3);
+ aSurrounding.put(b1);
+ aSurrounding.put(b2);
+ aSurrounding.put(b3);
+ aSurrounding.put(c1);
+ aSurrounding.put(c2);
+ aSurrounding.put(c3);
+ for (Chunk r : aSurrounding) {
+ mCurrentChunkPollution += getPollutionInChunk(r);
+ }
+ }
+ if (mCurrentChunkPollution > 0) {
+ mHasPollution = true;
+ } else {
+ mHasPollution = false;
+ }
+ return mCurrentChunkPollution;
+ }
+
+ public int getPollutionInChunk(Chunk aChunk) {
+ int mCurrentChunkPollution = PollutionUtils.getPollution(aChunk);
+ if (mCurrentChunkPollution > 0) {
+ mHasPollution = true;
+ } else {
+ mHasPollution = false;
+ }
+ return mCurrentChunkPollution;
+ }
+
+ public boolean hasRotor(ItemStack rotorStack) {
+ if (rotorStack != null) {
+ if (rotorStack.getItem() instanceof ItemBasicScrubberTurbine) {
+ // Logger.INFO("Found Basic Turbine Rotor.");
+ return true;
+ } else if (rotorStack.getItem() instanceof GT_MetaGenerated_Tool && rotorStack.getItemDamage() >= 170
+ && rotorStack.getItemDamage() <= 179) {
+ // Logger.INFO("Found Turbine Rotor.");
+ return true;
+ } else {
+ // Logger.INFO("Found: "+rotorStack.getDisplayName()+":"+rotorStack.getItemDamage());
+ }
+ }
+ // Logger.INFO("Found No Turbine Rotor.");
+ return false;
+ }
+
+ public boolean damageTurbineRotor() {
+ try {
+
+ boolean creativeRotor = false;
+ ItemStack rotorStack = this.mInventory[SLOT_ROTOR];
+ if (rotorStack == null) {
+ return false;
+ } else if (rotorStack.getItem() instanceof ItemBasicScrubberTurbine) {
+ long currentUse = ItemBasicScrubberTurbine.getFilterDamage(rotorStack);
+ // Remove broken Filter
+ if (rotorStack.getItemDamage() == 0 && currentUse >= 2000 - 10) {
+ Logger.INFO("Depleting ItemBasicScrubberTurbine T1");
+ this.mInventory[this.SLOT_FILTER] = null;
+ return false;
+ } else if (rotorStack.getItemDamage() == 1 && currentUse >= 4000 - 10) {
+ Logger.INFO("Depleting ItemBasicScrubberTurbine T2");
+ this.mInventory[this.SLOT_FILTER] = null;
+ return false;
+ } else if (rotorStack.getItemDamage() == 2 && currentUse >= 6000 - 10) {
+ Logger.INFO("Depleting ItemBasicScrubberTurbine T3");
+ this.mInventory[this.SLOT_FILTER] = null;
+ return false;
+ } else {
+ // Do Damage
+ Logger.INFO("Damaging ItemBasicScrubberTurbine");
+ ItemBasicScrubberTurbine.setFilterDamage(rotorStack, currentUse + 10);
+ Logger.INFO("Rotor Damage: " + currentUse);
+ return true;
+ }
+ } else if (rotorStack.getItem() instanceof GT_MetaGenerated_Tool_01) {
+ Materials t1 = GT_MetaGenerated_Tool.getPrimaryMaterial(rotorStack);
+ Materials t2 = GT_MetaGenerated_Tool.getSecondaryMaterial(rotorStack);
+ if (t1 == Materials._NULL && t2 == Materials._NULL) {
+ Logger.INFO("Found creative rotor.");
+ creativeRotor = true;
+ }
+ } else {
+ Logger.INFO("Bad item in rotor slot.");
+ return false;
+ }
+
+ if (mInventory[SLOT_ROTOR].getItem() instanceof GT_MetaGenerated_Tool_01
+ && ((GT_MetaGenerated_Tool) mInventory[SLOT_ROTOR].getItem()).getToolStats(mInventory[SLOT_ROTOR])
+ .getSpeedMultiplier() > 0
+ && GT_MetaGenerated_Tool.getPrimaryMaterial(mInventory[SLOT_ROTOR]).mToolSpeed > 0) {
+
+ long damageValue = (long) Math
+ .floor(Math.abs(MathUtils.randFloat(1, 2) - MathUtils.randFloat(1, 3)) * (1 + 3 - 1) + 1);
+ double fDam = Math
+ .floor(Math.abs(MathUtils.randFloat(1f, 2f) - MathUtils.randFloat(1f, 2f)) * (1f + 2f - 1f) + 1f);
+ damageValue -= fDam;
+
+ // Logger.INFO("Trying to do "+damageValue+" damage to the rotor. ["+fDam+"]");
+ /*
+ * Materials M1 = GT_MetaGenerated_Tool.getPrimaryMaterial(this.mInventory[this.SLOT_ROTOR]); Materials
+ * M2 = GT_MetaGenerated_Tool.getSecondaryMaterial(this.mInventory[this.SLOT_ROTOR]);
+ * Logger.INFO("Trying to do "+damageValue+" damage to the rotor. [2]");
+ */
+
+ // Damage Rotor
+ // int rotorDurability = this.mInventory[this.SLOT_ROTOR].getItemDamage();
+ long rotorDamage = creativeRotor ? 0
+ : GT_MetaGenerated_Tool.getToolDamage(this.mInventory[this.SLOT_ROTOR]);
+ long rotorDurabilityMax = creativeRotor ? Integer.MAX_VALUE
+ : GT_MetaGenerated_Tool.getToolMaxDamage(this.mInventory[this.SLOT_ROTOR]);
+ long rotorDurability = (rotorDurabilityMax - rotorDamage);
+ Logger.INFO(
+ "Rotor Damage: " + rotorDamage
+ + " | Max Durability: "
+ + rotorDurabilityMax
+ + " | "
+ + " Remaining Durability: "
+ + rotorDurability);
+ if (rotorDurability >= damageValue) {
+
+ if (!mSaveRotor) {
+ Logger.INFO("Damaging Rotor.");
+
+ if (!creativeRotor) GT_ModHandler
+ .damageOrDechargeItem(this.mInventory[this.SLOT_ROTOR], (int) damageValue, 0, null);
+
+ long tempDur = GT_MetaGenerated_Tool.getToolDamage(this.mInventory[this.SLOT_ROTOR]);
+ if (tempDur < rotorDurabilityMax) {
+ return true;
+ } else {
+ rotorDurability = 0;
+ }
+ } else {
+ Logger.INFO("Damaging Rotor.");
+ if (rotorDurability > 1000) {
+ if (!creativeRotor) GT_ModHandler
+ .damageOrDechargeItem(this.mInventory[this.SLOT_ROTOR], (int) damageValue / 2, 0, null);
+ long tempDur = GT_MetaGenerated_Tool.getToolDamage(this.mInventory[this.SLOT_ROTOR]);
+ if (tempDur < rotorDurabilityMax) {
+ return true;
+ } else {
+ rotorDurability = 0;
+ }
+ }
+ }
+ }
+
+ if (rotorDurability <= 0 && !mSaveRotor && !creativeRotor) {
+ Logger.INFO("Destroying Rotor.");
+ this.mInventory[this.SLOT_ROTOR] = null;
+ return false;
+ } else if (rotorDurability <= 0 && mSaveRotor) {
+ Logger.INFO("Saving Rotor.");
+ return false;
+ }
+
+ } else {
+ Logger.INFO("Bad Rotor.");
+ return false;
+ }
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ return false;
+ }
+
+ public int getFreeSpaces() {
+ int mAir = 0;
+ IGregTechTileEntity aBaseMetaTileEntity = this.getBaseMetaTileEntity();
+ if (aBaseMetaTileEntity.getAirOffset(1, 0, 0)) {
+ mAir++;
+ }
+ if (aBaseMetaTileEntity.getAirOffset(-1, 0, 0)) {
+ mAir++;
+ }
+ if (aBaseMetaTileEntity.getAirOffset(0, 0, 1)) {
+ mAir++;
+ }
+ if (aBaseMetaTileEntity.getAirOffset(0, 0, -1)) {
+ mAir++;
+ }
+ if (aBaseMetaTileEntity.getAirOffset(0, 1, 0)) {
+ mAir++;
+ }
+ if (aBaseMetaTileEntity.getAirOffset(0, -1, 0)) {
+ mAir++;
+ }
+ return mAir;
+ }
+
+ public boolean removePollution(int toRemove) {
+
+ if (this == null || this.getBaseMetaTileEntity() == null
+ || this.getBaseMetaTileEntity()
+ .getWorld() == null) {
+ return false;
+ }
+
+ if (this.mTier < 7) {
+ int startPollution = getCurrentChunkPollution();
+ Logger.INFO("Current Chunk Pollution: " + startPollution);
+ PollutionUtils.removePollution(this.getBaseMetaTileEntity(), toRemove);
+ int after = getCurrentChunkPollution();
+ Logger.INFO("Current Chunk Pollution: " + after);
+ return (after < startPollution);
+ } else {
+ int chunksWithRemoval = 0;
+ int totalRemoved = 0;
+ AutoMap<Chunk> aSurrounding = new AutoMap<>();
+ Chunk aThisChunk = this.getBaseMetaTileEntity()
+ .getWorld()
+ .getChunkFromBlockCoords(
+ this.getBaseMetaTileEntity()
+ .getXCoord(),
+ this.getBaseMetaTileEntity()
+ .getZCoord());
+ int mainChunkX = aThisChunk.xPosition;
+ int mainChunkZ = aThisChunk.zPosition;
+
+ World aWorld = this.getBaseMetaTileEntity()
+ .getWorld();
+ int xPos = this.getBaseMetaTileEntity()
+ .getXCoord();
+ int zPos = this.getBaseMetaTileEntity()
+ .getZCoord();
+
+ Chunk a1 = aWorld.getChunkFromBlockCoords(xPos - 32, zPos - 32);
+ Chunk a2 = aWorld.getChunkFromBlockCoords(xPos - 32, zPos);
+ Chunk a3 = aWorld.getChunkFromBlockCoords(xPos - 32, zPos + 32);
+ Chunk b1 = aWorld.getChunkFromBlockCoords(xPos, zPos - 32);
+ Chunk b2 = aWorld.getChunkFromBlockCoords(xPos, zPos);
+ Chunk b3 = aWorld.getChunkFromBlockCoords(xPos, zPos + 32);
+ Chunk c1 = aWorld.getChunkFromBlockCoords(xPos + 32, zPos - 32);
+ Chunk c2 = aWorld.getChunkFromBlockCoords(xPos + 32, zPos);
+ Chunk c3 = aWorld.getChunkFromBlockCoords(xPos + 32, zPos + 32);
+
+ aSurrounding.put(a1);
+ aSurrounding.put(a2);
+ aSurrounding.put(a3);
+ aSurrounding.put(b1);
+ aSurrounding.put(b2);
+ aSurrounding.put(b3);
+ aSurrounding.put(c1);
+ aSurrounding.put(c2);
+ aSurrounding.put(c3);
+
+ for (Chunk r : aSurrounding) {
+ if (!r.isChunkLoaded) {
+ continue;
+ }
+
+ int startPollution = getPollutionInChunk(r);
+ if (startPollution == 0) {
+ continue;
+ }
+
+ Logger.INFO(
+ "Trying to remove pollution from chunk " + r.xPosition
+ + ", "
+ + r.zPosition
+ + " | "
+ + startPollution);
+ int after = 0;
+ boolean isMainChunk = r.isAtLocation(mainChunkX, mainChunkZ);
+
+ int removal = Math.max(0, !isMainChunk ? (toRemove / 4) : toRemove);
+ if (removePollution(r, removal)) {
+ chunksWithRemoval++;
+ after = getPollutionInChunk(r);
+ } else {
+ after = 0;
+ }
+ if (startPollution - after > 0) {
+ totalRemoved += (startPollution - after);
+ }
+ Logger.INFO(
+ "Removed " + (startPollution - after)
+ + " pollution from chunk "
+ + r.xPosition
+ + ", "
+ + r.zPosition
+ + " | "
+ + after);
+ }
+ return totalRemoved > 0 && chunksWithRemoval > 0;
+ }
+ }
+
+ public boolean removePollution(Chunk aChunk, int toRemove) {
+ int before = getCurrentChunkPollution();
+ PollutionUtils.removePollution(aChunk, toRemove);
+ int after = getCurrentChunkPollution();
+ return (after < before);
+ }
+
+ public boolean hasAirFilter(ItemStack filter) {
+ if (filter == null) {
+ return false;
+ }
+ return filter.getItem() instanceof ItemAirFilter;
+ }
+
+ public boolean damageAirFilter() {
+ ItemStack filter = this.mInventory[this.SLOT_FILTER];
+ if (filter == null) {
+ return false;
+ }
+
+ boolean creativeRotor = false;
+ ItemStack rotorStack = this.mInventory[SLOT_ROTOR];
+ if (rotorStack != null) {
+ if (rotorStack.getItem() instanceof GT_MetaGenerated_Tool_01) {
+ Materials t1 = GT_MetaGenerated_Tool.getPrimaryMaterial(rotorStack);
+ Materials t2 = GT_MetaGenerated_Tool.getSecondaryMaterial(rotorStack);
+ if (t1 == Materials._NULL && t2 == Materials._NULL) {
+ creativeRotor = true;
+ }
+ }
+ }
+
+ if (creativeRotor) {
+ return true;
+ }
+
+ if (filter.getItem() instanceof ItemAirFilter) {
+
+ long currentUse = ItemAirFilter.getFilterDamage(filter);
+
+ // Remove broken Filter
+ if (filter.getItemDamage() == 0 && currentUse >= 50 - 1) {
+ this.mInventory[this.SLOT_FILTER] = null;
+ return false;
+ } else if (filter.getItemDamage() == 1 && currentUse >= 2500 - 1) {
+ this.mInventory[this.SLOT_FILTER] = null;
+ return false;
+ } else {
+ // Do Damage
+ ItemAirFilter.setFilterDamage(filter, currentUse + 1);
+ Logger.INFO("Filter Damage: " + currentUse);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean canInsertItem(int aIndex, ItemStack aStack, int ordinalSide) {
+ if (aIndex == SLOT_FILTER) {
+ if (aStack.getItem() instanceof ItemAirFilter) {
+ Logger.INFO("Inserting Air Filter into " + aIndex);
+ return true;
+ }
+ }
+ if (aIndex == SLOT_ROTOR) {
+ if (this.mInventory[7] != null) {
+ Logger.INFO("Found conveyor, can automate turbines. Inserting into " + aIndex);
+ if (aStack.getItem() instanceof ItemBasicScrubberTurbine) {
+ return true;
+ }
+ if (aStack.getItem() instanceof GT_MetaGenerated_Tool && aStack.getItemDamage() >= 170
+ && aStack.getItemDamage() <= 179) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+ super.onScrewdriverRightClick(side, aPlayer, aX, aY, aZ);
+ }
+
+ @Override
+ public void doSound(byte aIndex, double aX, double aY, double aZ) {
+ if (aIndex == -120) {
+ GT_Utility
+ .doSoundAtClient(SoundResource.IC2_TOOLS_BATTERY_USE, MathUtils.randInt(5, 50), 0.05F, aX, aY, aZ);
+ } else {
+ super.doSound((byte) 0, aX, aY, aZ);
+ }
+ }
+
+ @Override
+ public String[] getInfoData() {
+ AutoMap<String> aTooltipSuper = new AutoMap<>();
+ for (String s : super.getInfoData()) {
+ aTooltipSuper.put(s);
+ }
+ int mAirSides = getFreeSpaces();
+ int reduction = 0;
+
+ try {
+ long tVoltage = maxEUInput();
+ byte tTier = (byte) Math.max(1, GT_Utility.getTier(tVoltage));
+ reduction += (((Math.max((tTier - 2), 1) * 2) * 50) * mAirSides);
+ reduction = (MathUtils.safeInt((long) reduction * this.mBaseEff) / 100000) * mAirSides
+ * Math.max((tTier - 2), 1);
+ reduction = MathUtils.safeInt(((long) reduction / 100) * this.mOptimalAirFlow);
+
+ aTooltipSuper.put("Maximum pollution removed per second: " + reduction);
+ } catch (Throwable t) {
+ aTooltipSuper.put("Maximum pollution removed per second: " + mPollutionReduction);
+ }
+ aTooltipSuper.put("Air Sides: " + mAirSides);
+
+ String[] mBuiltOutput = new String[aTooltipSuper.size()];
+ int aIndex = 0;
+ for (String i : aTooltipSuper) {
+ mBuiltOutput[aIndex++] = i;
+ }
+
+ return mBuiltOutput;
+ }
+
+ @Override
+ public boolean isGivingInformation() {
+ return true;
+ }
+
+ @Override
+ public boolean allowCoverOnSide(ForgeDirection side, GT_ItemStack aCoverID) {
+ if (side.offsetY != 0) {
+ return false;
+ }
+ return super.allowCoverOnSide(side, aCoverID);
+ }
+
+ @Override
+ public ITexture[] getTopFacingInactive(byte aColor) {
+ return super.getTopFacingInactive(aColor);
+ }
+
+ @Override
+ public void setItemNBT(NBTTagCompound aNBT) {
+ aNBT.setInteger("mOptimalAirFlow", this.mOptimalAirFlow);
+ aNBT.setBoolean("mSaveRotor", mSaveRotor);
+ super.setItemNBT(aNBT);
+ }
+
+ private static ItemStack[] sGregTurbines;
+
+ public static ItemStack getTieredTurbine(int aTier) {
+ if (sGregTurbines == null) {
+ sGregTurbines = new ItemStack[3];
+ sGregTurbines[0] = GT_MetaGenerated_Tool.sInstances.get("gt.metatool.01")
+ .getToolWithStats(GT_MetaGenerated_Tool_01.TURBINE_SMALL, 1, Materials.Iron, Materials.Iron, null);
+ sGregTurbines[1] = GT_MetaGenerated_Tool.sInstances.get("gt.metatool.01")
+ .getToolWithStats(GT_MetaGenerated_Tool_01.TURBINE_SMALL, 1, Materials.Bronze, Materials.Bronze, null);
+ sGregTurbines[2] = GT_MetaGenerated_Tool.sInstances.get("gt.metatool.01")
+ .getToolWithStats(GT_MetaGenerated_Tool_01.TURBINE_SMALL, 1, Materials.Steel, Materials.Steel, null);
+ } else {
+ return sGregTurbines[aTier];
+ }
+
+ return null;
+ }
+
+ public int getBaseEfficiency(ItemStack aStackRotor) {
+ if (aStackRotor.getItem() instanceof ItemBasicScrubberTurbine) {
+ return getBaseEfficiency(getTieredTurbine(aStackRotor.getItemDamage()));
+ }
+ return (int) ((50.0F
+ + (10.0F * ((GT_MetaGenerated_Tool) aStackRotor.getItem()).getToolCombatDamage(aStackRotor))) * 100);
+ }
+
+ public int getOptimalAirFlow(ItemStack aStackRotor) {
+ if (aStackRotor.getItem() instanceof ItemBasicScrubberTurbine) {
+ return getOptimalAirFlow(getTieredTurbine(aStackRotor.getItemDamage()));
+ }
+ return (int) Math.max(
+ Float.MIN_NORMAL,
+ ((GT_MetaGenerated_Tool) aStackRotor.getItem()).getToolStats(aStackRotor)
+ .getSpeedMultiplier() * GT_MetaGenerated_Tool.getPrimaryMaterial(aStackRotor).mToolSpeed * 50);
+ }
+
+ @Override
+ public boolean useModularUI() {
+ return true;
+ }
+
+ @Override
+ public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) {
+ builder.widget(new SlotWidget(inventoryHandler, SLOT_ROTOR).setFilter(stack -> {
+ if (stack.getItem() instanceof ItemBasicScrubberTurbine) {
+ return true;
+ }
+ return stack.getItem() instanceof GT_MetaGenerated_Tool && stack.getItemDamage() >= 170
+ && stack.getItemDamage() <= 179;
+ })
+ .setBackground(getGUITextureSet().getItemSlot(), GTPP_UITextures.OVERLAY_SLOT_TURBINE)
+ .setPos(52, 24))
+ .widget(
+ new SlotWidget(inventoryHandler, SLOT_FILTER)
+ .setFilter(stack -> stack.getItem() instanceof ItemAirFilter)
+ .setBackground(getGUITextureSet().getItemSlot(), GT_UITextures.OVERLAY_SLOT_RECYCLE)
+ .setPos(106, 24))
+ .widget(
+ new SlotWidget(inventoryHandler, 7)
+ .setFilter(stack -> GT_Utility.areStacksEqual(stack, CI.getConveyor(mTier, 1), true))
+ .setPos(124, 62));
+ builder.widget(
+ new DrawableWidget().setDrawable(GT_UITextures.PICTURE_INFORMATION)
+ .dynamicTooltip(() -> Collections.singletonList("Reduction: " + mPollutionReduction + "/s"))
+ .attachSyncer(
+ new FakeSyncWidget.IntegerSyncer(() -> mPollutionReduction, val -> mPollutionReduction = val),
+ builder,
+ (widget, val) -> widget.notifyTooltipChange())
+ .setPos(163, 5)
+ .setSize(7, 18));
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GregtechMetaPollutionCreator.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GregtechMetaPollutionCreator.java
new file mode 100644
index 0000000000..d7b6b8fffd
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GregtechMetaPollutionCreator.java
@@ -0,0 +1,458 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.basic;
+
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.world.World;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import gregtech.api.enums.Textures;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.objects.GT_RenderedTexture;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.minecraft.PlayerUtils;
+import gtPlusPlus.core.util.minecraft.gregtech.PollutionUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMetaTileEntity;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaPollutionCreator extends GregtechMetaTileEntity {
+
+ int mCurrentPollution;
+ int mAveragePollution;
+ int mAveragePollutionArray[] = new int[10];
+ private int mArrayPos = 0;
+ private int mTickTimer = 0;
+ private int mSecondTimer = 0;
+
+ public GregtechMetaPollutionCreator(final int aID, final String aName, final String aNameRegional, final int aTier,
+ final String aDescription, final int aSlotCount) {
+ super(aID, aName, aNameRegional, aTier, aSlotCount, aDescription);
+ }
+
+ public GregtechMetaPollutionCreator(final String aName, final int aTier, final String aDescription,
+ final ITexture[][][] aTextures, final int aSlotCount) {
+ super(aName, aTier, aSlotCount, aDescription, aTextures);
+ }
+
+ @Override
+ public String[] getDescription() {
+ return new String[] { this.mDescription, "A useful debug machine to create pollution.", CORE.GT_Tooltip.get() };
+ }
+
+ @Override
+ public ITexture[][][] getTextureSet(final ITexture[] aTextures) {
+ final ITexture[][][] rTextures = new ITexture[10][17][];
+ for (byte i = -1; i < 16; i++) {
+ rTextures[0][i + 1] = this.getFront(i);
+ rTextures[1][i + 1] = this.getBack(i);
+ rTextures[2][i + 1] = this.getBottom(i);
+ rTextures[3][i + 1] = this.getTop(i);
+ rTextures[4][i + 1] = this.getSides(i);
+ rTextures[5][i + 1] = this.getFrontActive(i);
+ rTextures[6][i + 1] = this.getBackActive(i);
+ rTextures[7][i + 1] = this.getBottomActive(i);
+ rTextures[8][i + 1] = this.getTopActive(i);
+ rTextures[9][i + 1] = this.getSidesActive(i);
+ }
+ return rTextures;
+ }
+
+ @Override
+ public ITexture[] getTexture(final IGregTechTileEntity aBaseMetaTileEntity, final ForgeDirection side,
+ final ForgeDirection facing, final int aColorIndex, final boolean aActive, final boolean aRedstone) {
+ return this.mTextures[(aActive ? 5 : 0) + (side == facing ? 0
+ : side == facing.getOpposite() ? 1
+ : side == ForgeDirection.DOWN ? 2 : side == ForgeDirection.UP ? 3 : 4)][aColorIndex + 1];
+ }
+
+ public ITexture[] getFront(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier + 3][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Screen_2) };
+ }
+
+ public ITexture[] getBack(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier + 3][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ public ITexture[] getBottom(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier + 3][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ public ITexture[] getTop(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier + 3][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ public ITexture[] getSides(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier + 3][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ public ITexture[] getFrontActive(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier + 3][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Screen_2) };
+ }
+
+ public ITexture[] getBackActive(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier + 3][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ public ITexture[] getBottomActive(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier + 3][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ public ITexture[] getTopActive(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier + 3][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ public ITexture[] getSidesActive(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier + 3][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ @Override
+ public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+ if (pollutionMultiplier > 99) {
+ pollutionMultiplier = 1;
+ } else {
+ pollutionMultiplier++;
+ }
+ PlayerUtils.messagePlayer(aPlayer, "Pollution Mutliplier is now " + pollutionMultiplier + ".");
+ super.onScrewdriverRightClick(side, aPlayer, aX, aY, aZ);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaPollutionCreator(
+ this.mName,
+ this.mTier,
+ this.mDescription,
+ this.mTextures,
+ this.mInventory.length);
+ }
+
+ @Override
+ public boolean isSimpleMachine() {
+ return false;
+ }
+
+ @Override
+ public boolean isElectric() {
+ return true;
+ }
+
+ @Override
+ public boolean isValidSlot(final int aIndex) {
+ return true;
+ }
+
+ @Override
+ public boolean isFacingValid(final ForgeDirection facing) {
+ return true;
+ }
+
+ @Override
+ public boolean isEnetInput() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnetOutput() {
+ return false;
+ }
+
+ @Override
+ public boolean isInputFacing(final ForgeDirection side) {
+ return side != this.getBaseMetaTileEntity()
+ .getFrontFacing();
+ }
+
+ @Override
+ public boolean isOutputFacing(final ForgeDirection side) {
+ return side == this.getBaseMetaTileEntity()
+ .getFrontFacing();
+ }
+
+ @Override
+ public boolean isTeleporterCompatible() {
+ return false;
+ }
+
+ @Override
+ public long getMinimumStoredEU() {
+ return 0;
+ }
+
+ @Override
+ public long maxEUStore() {
+ return 0;
+ }
+
+ @Override
+ public int getCapacity() {
+ return 0;
+ }
+
+ @Override
+ public long maxEUInput() {
+ return 0;
+ }
+
+ @Override
+ public long maxEUOutput() {
+ return 0;
+ }
+
+ @Override
+ public long maxAmperesIn() {
+ return 0;
+ }
+
+ @Override
+ public long maxAmperesOut() {
+ return 0;
+ }
+
+ @Override
+ public int rechargerSlotStartIndex() {
+ return 0;
+ }
+
+ @Override
+ public int dechargerSlotStartIndex() {
+ return 0;
+ }
+
+ @Override
+ public int rechargerSlotCount() {
+ return 0;
+ }
+
+ @Override
+ public int dechargerSlotCount() {
+ return 0;
+ }
+
+ @Override
+ public int getProgresstime() {
+ return (int) this.getBaseMetaTileEntity()
+ .getUniversalEnergyStored();
+ }
+
+ @Override
+ public int maxProgresstime() {
+ return (int) this.getBaseMetaTileEntity()
+ .getUniversalEnergyCapacity();
+ }
+
+ @Override
+ public boolean isAccessAllowed(final EntityPlayer aPlayer) {
+ return true;
+ }
+
+ @Override
+ public boolean onRightclick(final IGregTechTileEntity aBaseMetaTileEntity, final EntityPlayer aPlayer) {
+ if (aBaseMetaTileEntity.isClientSide()) {
+ return true;
+ }
+ this.showPollution(aPlayer.getEntityWorld(), aPlayer);
+ return true;
+ }
+
+ public int pollutionMultiplier = 1;
+
+ private void showPollution(final World worldIn, final EntityPlayer playerIn) {
+ if (!PollutionUtils.isPollutionEnabled()) {
+ PlayerUtils.messagePlayer(playerIn, "This block is useless, Pollution is disabled.");
+ } else {
+ addPollution();
+ PlayerUtils
+ .messagePlayer(playerIn, "This chunk now contains " + getCurrentChunkPollution() + " pollution.");
+ // PlayerUtils.messagePlayer(playerIn, "Average over last ten minutes: "+getAveragePollutionOverLastTen()+"
+ // pollution.");
+ }
+ }
+
+ private boolean addPollution() {
+ PollutionUtils.addPollution(getBaseMetaTileEntity(), 100000 * pollutionMultiplier);
+ return true;
+ }
+
+ @Override
+ public boolean allowPullStack(final IGregTechTileEntity aBaseMetaTileEntity, final int aIndex,
+ final ForgeDirection side, final ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public boolean allowPutStack(final IGregTechTileEntity aBaseMetaTileEntity, final int aIndex,
+ final ForgeDirection side, final ItemStack aStack) {
+ return false;
+ }
+
+ public int getCurrentChunkPollution() {
+ return getCurrentChunkPollution(this.getBaseMetaTileEntity());
+ }
+
+ public int getCurrentChunkPollution(IGregTechTileEntity aBaseMetaTileEntity) {
+ return PollutionUtils.getPollution(aBaseMetaTileEntity);
+ }
+
+ @Override
+ public String[] getInfoData() {
+ return new String[] { this.getLocalName(), "Current Pollution: " + this.mCurrentPollution,
+ "Average/10 minutes:" + getAveragePollutionOverLastTen() };
+ }
+
+ @Override
+ public boolean isGivingInformation() {
+ return true;
+ }
+
+ @Override
+ public int[] getAccessibleSlotsFromSide(final int p_94128_1_) {
+ return new int[] {};
+ }
+
+ @Override
+ public boolean canInsertItem(final int p_102007_1_, final ItemStack p_102007_2_, final int p_102007_3_) {
+ return false;
+ }
+
+ @Override
+ public boolean canExtractItem(final int p_102008_1_, final ItemStack p_102008_2_, final int p_102008_3_) {
+ return false;
+ }
+
+ @Override
+ public int getSizeInventory() {
+ return 0;
+ }
+
+ @Override
+ public ItemStack getStackInSlot(final int p_70301_1_) {
+ return null;
+ }
+
+ @Override
+ public ItemStack decrStackSize(final int p_70298_1_, final int p_70298_2_) {
+ return null;
+ }
+
+ @Override
+ public ItemStack getStackInSlotOnClosing(final int p_70304_1_) {
+ return null;
+ }
+
+ @Override
+ public void setInventorySlotContents(final int p_70299_1_, final ItemStack p_70299_2_) {}
+
+ @Override
+ public String getInventoryName() {
+ return null;
+ }
+
+ @Override
+ public boolean hasCustomInventoryName() {
+ return false;
+ }
+
+ @Override
+ public int getInventoryStackLimit() {
+ return 0;
+ }
+
+ @Override
+ public boolean isUseableByPlayer(final EntityPlayer p_70300_1_) {
+ return false;
+ }
+
+ @Override
+ public void openInventory() {}
+
+ @Override
+ public void closeInventory() {}
+
+ @Override
+ public boolean isItemValidForSlot(final int p_94041_1_, final ItemStack p_94041_2_) {
+ return false;
+ }
+
+ @Override
+ public boolean isOverclockerUpgradable() {
+ return false;
+ }
+
+ @Override
+ public boolean isTransformerUpgradable() {
+ return false;
+ }
+
+ @Override
+ public void saveNBTData(final NBTTagCompound aNBT) {
+ aNBT.setInteger("mCurrentPollution", this.mCurrentPollution);
+ aNBT.setInteger("mAveragePollution", this.mAveragePollution);
+ }
+
+ @Override
+ public void loadNBTData(final NBTTagCompound aNBT) {
+ this.mCurrentPollution = aNBT.getInteger("mCurrentPollution");
+ this.mAveragePollution = aNBT.getInteger("mAveragePollution");
+ }
+
+ @Override
+ public void onFirstTick(final IGregTechTileEntity aBaseMetaTileEntity) {
+ if (this.getBaseMetaTileEntity()
+ .isServerSide()) {
+ if (this.mCurrentPollution == 0) {
+ this.mCurrentPollution = getCurrentChunkPollution();
+ }
+ if (this.mArrayPos < 0 || this.mArrayPos > 9) {
+ this.mArrayPos = 0;
+ }
+ this.mTickTimer = 0;
+ }
+ }
+
+ @Override
+ public void onPostTick(final IGregTechTileEntity aBaseMetaTileEntity, final long aTick) {
+ super.onPostTick(aBaseMetaTileEntity, aTick);
+ if (this.getBaseMetaTileEntity()
+ .isServerSide()) {
+ // TickTimer - 20 times a second
+ this.mTickTimer++;
+ if (mTickTimer % 20 == 0) {
+ this.mCurrentPollution = getCurrentChunkPollution();
+ }
+ }
+ }
+
+ public int getAveragePollutionOverLastTen() {
+ int counter = 0;
+ int total = 0;
+
+ for (int j : this.mAveragePollutionArray) {
+ if (j != 0) {
+ total += j;
+ counter++;
+ }
+ }
+ int returnValue = 0;
+ if (total > 0 && counter > 0) {
+ returnValue = (total / counter);
+ this.mAveragePollution = returnValue;
+ } else {
+ returnValue = getCurrentChunkPollution();
+ }
+ // Logger.INFO("| DEBUG: "+returnValue +" | ArrayPos:"+this.mArrayPos+" | Counter:"+counter+" | Total:"+total+"
+ // |");
+ return returnValue;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GregtechMetaPollutionDetector.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GregtechMetaPollutionDetector.java
new file mode 100644
index 0000000000..92443d2658
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GregtechMetaPollutionDetector.java
@@ -0,0 +1,502 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.basic;
+
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.world.World;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import gregtech.api.enums.Textures;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.objects.GT_RenderedTexture;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.math.MathUtils;
+import gtPlusPlus.core.util.minecraft.PlayerUtils;
+import gtPlusPlus.core.util.minecraft.gregtech.PollutionUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMetaTileEntity;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaPollutionDetector extends GregtechMetaTileEntity {
+
+ int mCurrentPollution;
+ int mAveragePollution;
+ int mAveragePollutionArray[] = new int[10];
+ private int mArrayPos = 0;
+ private int mTickTimer = 0;
+ private int mSecondTimer = 0;
+ private long mRedstoneLevel = 0;
+
+ public GregtechMetaPollutionDetector(final int aID, final String aName, final String aNameRegional, final int aTier,
+ final String aDescription, final int aSlotCount) {
+ super(aID, aName, aNameRegional, aTier, aSlotCount, aDescription);
+ }
+
+ public GregtechMetaPollutionDetector(final String aName, final int aTier, final String aDescription,
+ final ITexture[][][] aTextures, final int aSlotCount) {
+ super(aName, aTier, aSlotCount, aDescription, aTextures);
+ }
+
+ @Override
+ public String[] getDescription() {
+ return new String[] { this.mDescription, "Right click to check pollution levels.",
+ "Configure with screwdriver to set redstone output amount.", "Does not use power.", CORE.GT_Tooltip.get() };
+ }
+
+ @Override
+ public ITexture[] getTexture(final IGregTechTileEntity aBaseMetaTileEntity, final ForgeDirection side,
+ final ForgeDirection facing, final int aColorIndex, final boolean aActive, final boolean aRedstone) {
+ return side == facing
+ ? new ITexture[] { new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Dimensional),
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Screen_Frequency) }
+ : new ITexture[] { new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Dimensional),
+ new GT_RenderedTexture(Textures.BlockIcons.VOID) };
+ }
+
+ @Override
+ public ITexture[][][] getTextureSet(final ITexture[] aTextures) {
+ final ITexture[][][] rTextures = new ITexture[10][17][];
+ for (byte i = -1; i < 16; i++) {
+ rTextures[0][i + 1] = this.getFront(i);
+ rTextures[1][i + 1] = this.getBack(i);
+ rTextures[2][i + 1] = this.getBottom(i);
+ rTextures[3][i + 1] = this.getTop(i);
+ rTextures[4][i + 1] = this.getSides(i);
+ rTextures[5][i + 1] = this.getFrontActive(i);
+ rTextures[6][i + 1] = this.getBackActive(i);
+ rTextures[7][i + 1] = this.getBottomActive(i);
+ rTextures[8][i + 1] = this.getTopActive(i);
+ rTextures[9][i + 1] = this.getSidesActive(i);
+ }
+ return rTextures;
+ }
+
+ /*
+ * @Override public ITexture[] getTexture(final IGregTechTileEntity aBaseMetaTileEntity, final byte aSide, final
+ * byte aFacing, final int aColorIndex, final boolean aActive, final boolean aRedstone) { return
+ * this.mTextures[(aActive ? 5 : 0) + (side == facing ? 0 : side == facing.getOpposite() ? 1 : side ==
+ * ForgeDirection.DOWN ? 2 : side == ForgeDirection.UP ? 3 : 4)][aColorIndex + 1]; }
+ */
+
+ public ITexture[] getFront(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Screen_2) };
+ }
+
+ public ITexture[] getBack(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ public ITexture[] getBottom(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ public ITexture[] getTop(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ public ITexture[] getSides(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ public ITexture[] getFrontActive(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Screen_2) };
+ }
+
+ public ITexture[] getBackActive(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ public ITexture[] getBottomActive(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ public ITexture[] getTopActive(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ public ITexture[] getSidesActive(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaPollutionDetector(
+ this.mName,
+ this.mTier,
+ this.mDescription,
+ this.mTextures,
+ this.mInventory.length);
+ }
+
+ @Override
+ public boolean isSimpleMachine() {
+ return false;
+ }
+
+ @Override
+ public boolean isElectric() {
+ return true;
+ }
+
+ @Override
+ public boolean isValidSlot(final int aIndex) {
+ return true;
+ }
+
+ @Override
+ public boolean isFacingValid(final ForgeDirection facing) {
+ return true;
+ }
+
+ @Override
+ public boolean isEnetInput() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnetOutput() {
+ return false;
+ }
+
+ @Override
+ public boolean isInputFacing(final ForgeDirection side) {
+ return side != this.getBaseMetaTileEntity()
+ .getFrontFacing();
+ }
+
+ @Override
+ public boolean isOutputFacing(final ForgeDirection side) {
+ return side == this.getBaseMetaTileEntity()
+ .getFrontFacing();
+ }
+
+ @Override
+ public boolean isTeleporterCompatible() {
+ return false;
+ }
+
+ @Override
+ public long getMinimumStoredEU() {
+ return 0;
+ }
+
+ @Override
+ public long maxEUStore() {
+ return 0;
+ }
+
+ @Override
+ public int getCapacity() {
+ return 0;
+ }
+
+ @Override
+ public long maxEUInput() {
+ return 0;
+ }
+
+ @Override
+ public long maxEUOutput() {
+ return 0;
+ }
+
+ @Override
+ public long maxAmperesIn() {
+ return 0;
+ }
+
+ @Override
+ public long maxAmperesOut() {
+ return 0;
+ }
+
+ @Override
+ public int rechargerSlotStartIndex() {
+ return 0;
+ }
+
+ @Override
+ public int dechargerSlotStartIndex() {
+ return 0;
+ }
+
+ @Override
+ public int rechargerSlotCount() {
+ return 0;
+ }
+
+ @Override
+ public int dechargerSlotCount() {
+ return 0;
+ }
+
+ @Override
+ public int getProgresstime() {
+ return (int) this.getBaseMetaTileEntity()
+ .getUniversalEnergyStored();
+ }
+
+ @Override
+ public int maxProgresstime() {
+ return (int) this.getBaseMetaTileEntity()
+ .getUniversalEnergyCapacity();
+ }
+
+ @Override
+ public boolean isAccessAllowed(final EntityPlayer aPlayer) {
+ return true;
+ }
+
+ @Override
+ public boolean onRightclick(final IGregTechTileEntity aBaseMetaTileEntity, final EntityPlayer aPlayer) {
+ if (aBaseMetaTileEntity.isClientSide()) {
+ return true;
+ }
+ this.showPollution(aPlayer.getEntityWorld(), aPlayer);
+ return true;
+ }
+
+ private void showPollution(final World worldIn, final EntityPlayer playerIn) {
+ if (!PollutionUtils.isPollutionEnabled()) {
+ PlayerUtils.messagePlayer(playerIn, "This block is useless, Pollution is disabled.");
+ } else {
+ PlayerUtils.messagePlayer(playerIn, "This chunk contains " + getCurrentChunkPollution() + " pollution.");
+ PlayerUtils.messagePlayer(playerIn, "Emit Redstone at pollution level: " + this.mRedstoneLevel);
+ }
+ }
+
+ @Override
+ public boolean allowPullStack(final IGregTechTileEntity aBaseMetaTileEntity, final int aIndex,
+ final ForgeDirection side, final ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public boolean allowPutStack(final IGregTechTileEntity aBaseMetaTileEntity, final int aIndex,
+ final ForgeDirection side, final ItemStack aStack) {
+ return false;
+ }
+
+ public int getCurrentChunkPollution() {
+ return getCurrentChunkPollution(this.getBaseMetaTileEntity());
+ }
+
+ public int getCurrentChunkPollution(IGregTechTileEntity aBaseMetaTileEntity) {
+ return PollutionUtils.getPollution(aBaseMetaTileEntity);
+ }
+
+ @Override
+ public String[] getInfoData() {
+ return new String[] { this.getLocalName(), "Current Pollution: " + this.mCurrentPollution,
+ "Average/10 Sec: " + this.mAveragePollution, "Emit Redstone at pollution level: " + this.mRedstoneLevel };
+ }
+
+ @Override
+ public boolean isGivingInformation() {
+ return true;
+ }
+
+ @Override
+ public int[] getAccessibleSlotsFromSide(final int p_94128_1_) {
+ return new int[] {};
+ }
+
+ @Override
+ public boolean canInsertItem(final int p_102007_1_, final ItemStack p_102007_2_, final int p_102007_3_) {
+ return false;
+ }
+
+ @Override
+ public boolean canExtractItem(final int p_102008_1_, final ItemStack p_102008_2_, final int p_102008_3_) {
+ return false;
+ }
+
+ @Override
+ public int getSizeInventory() {
+ return 0;
+ }
+
+ @Override
+ public ItemStack getStackInSlot(final int p_70301_1_) {
+ return null;
+ }
+
+ @Override
+ public ItemStack decrStackSize(final int p_70298_1_, final int p_70298_2_) {
+ return null;
+ }
+
+ @Override
+ public ItemStack getStackInSlotOnClosing(final int p_70304_1_) {
+ return null;
+ }
+
+ @Override
+ public void setInventorySlotContents(final int p_70299_1_, final ItemStack p_70299_2_) {}
+
+ @Override
+ public String getInventoryName() {
+ return null;
+ }
+
+ @Override
+ public boolean hasCustomInventoryName() {
+ return false;
+ }
+
+ @Override
+ public int getInventoryStackLimit() {
+ return 0;
+ }
+
+ @Override
+ public boolean isUseableByPlayer(final EntityPlayer p_70300_1_) {
+ return false;
+ }
+
+ @Override
+ public void openInventory() {}
+
+ @Override
+ public void closeInventory() {}
+
+ @Override
+ public boolean isItemValidForSlot(final int p_94041_1_, final ItemStack p_94041_2_) {
+ return false;
+ }
+
+ @Override
+ public boolean isOverclockerUpgradable() {
+ return false;
+ }
+
+ @Override
+ public boolean isTransformerUpgradable() {
+ return false;
+ }
+
+ @Override
+ public void saveNBTData(final NBTTagCompound aNBT) {
+ aNBT.setInteger("mCurrentPollution", this.mCurrentPollution);
+ aNBT.setInteger("mAveragePollution", this.mAveragePollution);
+ aNBT.setLong("mRedstoneLevel", this.mRedstoneLevel);
+ }
+
+ @Override
+ public void loadNBTData(final NBTTagCompound aNBT) {
+ this.mCurrentPollution = aNBT.getInteger("mCurrentPollution");
+ this.mAveragePollution = aNBT.getInteger("mAveragePollution");
+ this.mRedstoneLevel = aNBT.getLong("mRedstoneLevel");
+ }
+
+ @Override
+ public void onFirstTick(final IGregTechTileEntity aBaseMetaTileEntity) {
+ super.onFirstTick(aBaseMetaTileEntity);
+ }
+
+ public boolean allowCoverOnSide(final ForgeDirection side, final int aCoverID) {
+ return side != this.getBaseMetaTileEntity()
+ .getFrontFacing();
+ }
+
+ @Override
+ public void onPostTick(final IGregTechTileEntity aBaseMetaTileEntity, final long aTick) {
+ super.onPostTick(aBaseMetaTileEntity, aTick);
+
+ // Only Calc server-side
+ if (!this.getBaseMetaTileEntity()
+ .isServerSide()) {
+ return;
+ }
+ // Emit Redstone
+ if (this.getCurrentChunkPollution() >= this.mRedstoneLevel) {
+ for (final ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) {
+ this.getBaseMetaTileEntity()
+ .setStrongOutputRedstoneSignal(side, (byte) 16);
+ }
+ this.markDirty();
+ } else {
+ for (final ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) {
+ this.getBaseMetaTileEntity()
+ .setStrongOutputRedstoneSignal(side, (byte) 0);
+ }
+ this.markDirty();
+ }
+
+ // Do Math for stats
+ if (this.mTickTimer % 20 == 0) {
+ mCurrentPollution = this.getCurrentChunkPollution();
+ if (mArrayPos > mAveragePollutionArray.length - 1) {
+ mArrayPos = 0;
+ }
+ mAveragePollutionArray[mArrayPos] = mCurrentPollution;
+ mAveragePollution = getAveragePollutionOverLastTen();
+ mArrayPos++;
+ }
+ this.mTickTimer++;
+ }
+
+ public int getAveragePollutionOverLastTen() {
+ return MathUtils.getIntAverage(mAveragePollutionArray);
+ }
+
+ @Override
+ public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+
+ if (side == this.getBaseMetaTileEntity()
+ .getFrontFacing()) {
+ final float[] tCoords = GT_Utility.getClickedFacingCoords(side, aX, aY, aZ);
+ switch ((byte) ((byte) (int) (tCoords[0] * 2.0F) + (2 * (byte) (int) (tCoords[1] * 2.0F)))) {
+ case 0 -> this.mRedstoneLevel -= 5000;
+ case 1 -> this.mRedstoneLevel += 5000;
+ case 2 -> this.mRedstoneLevel -= 50000;
+ case 3 -> this.mRedstoneLevel += 50000;
+ }
+ this.markDirty();
+ GT_Utility.sendChatToPlayer(aPlayer, "Emit Redstone at Pollution Level: " + this.mRedstoneLevel);
+ }
+
+ super.onScrewdriverRightClick(side, aPlayer, aX, aY, aZ);
+ }
+
+ @Override
+ public boolean allowGeneralRedstoneOutput() {
+ if (this.getCurrentChunkPollution() >= this.mRedstoneLevel) {
+ this.markDirty();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer, ForgeDirection side,
+ float aX, float aY, float aZ) {
+ return super.onRightclick(aBaseMetaTileEntity, aPlayer, side, aX, aY, aZ);
+ }
+
+ @Override
+ public void onMachineBlockUpdate() {
+ super.onMachineBlockUpdate();
+ }
+
+ @Override
+ public boolean hasSidedRedstoneOutputBehavior() {
+ if (this.getCurrentChunkPollution() >= this.mRedstoneLevel) {
+ this.markDirty();
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GregtechMetaTileEntity_AutoChisel.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GregtechMetaTileEntity_AutoChisel.java
new file mode 100644
index 0000000000..751771f2b4
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GregtechMetaTileEntity_AutoChisel.java
@@ -0,0 +1,190 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.basic;
+
+import java.util.List;
+
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import org.apache.commons.lang3.ArrayUtils;
+
+import com.gtnewhorizons.modularui.api.drawable.FallbackableUITexture;
+import com.gtnewhorizons.modularui.api.drawable.IDrawable;
+import com.gtnewhorizons.modularui.api.math.Pos2d;
+import com.gtnewhorizons.modularui.common.widget.SlotWidget;
+
+import gregtech.api.enums.Textures.BlockIcons;
+import gregtech.api.gui.modularui.GT_UITextures;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.metatileentity.MetaTileEntity;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine;
+import gregtech.api.objects.GT_RenderedTexture;
+import gregtech.api.recipe.BasicUIProperties;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.util.minecraft.ItemUtils;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+import team.chisel.carving.Carving;
+
+public class GregtechMetaTileEntity_AutoChisel extends GT_MetaTileEntity_BasicMachine {
+
+ private ItemStack mInputCache;
+ private ItemStack mOutputCache;
+
+ public GregtechMetaTileEntity_AutoChisel(int aID, String aName, String aNameRegional, int aTier) {
+ super(
+ aID,
+ aName,
+ aNameRegional,
+ aTier,
+ 1,
+ "Chisels things, Gregtech style",
+ 1,
+ 1,
+ new ITexture[] { new GT_RenderedTexture(BlockIcons.OVERLAY_SIDE_MASSFAB_ACTIVE),
+ new GT_RenderedTexture(BlockIcons.OVERLAY_SIDE_MASSFAB),
+ new GT_RenderedTexture(BlockIcons.OVERLAY_FRONT_MULTI_SMELTER_ACTIVE),
+ new GT_RenderedTexture(BlockIcons.OVERLAY_FRONT_MULTI_SMELTER),
+ new GT_RenderedTexture(TexturesGtBlock.Overlay_MatterFab_Active),
+ new GT_RenderedTexture(TexturesGtBlock.Overlay_MatterFab),
+ new GT_RenderedTexture(BlockIcons.OVERLAY_BOTTOM_MASSFAB_ACTIVE),
+ new GT_RenderedTexture(BlockIcons.OVERLAY_BOTTOM_MASSFAB) });
+ }
+
+ public GregtechMetaTileEntity_AutoChisel(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) {
+ super(aName, aTier, 1, aDescription, aTextures, 1, 1);
+ }
+
+ @Override
+ public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_AutoChisel(this.mName, this.mTier, this.mDescriptionArray, this.mTextures);
+ }
+
+ @Override
+ public String[] getDescription() {
+ return ArrayUtils.addAll(
+ this.mDescriptionArray,
+ "What you want to chisel goes in slot 1",
+ "What you want to get goes in the special slot (bottom right)",
+ "If special slot is empty, first chisel result is used");
+ }
+
+ private boolean hasValidCache(ItemStack aStack, ItemStack aSpecialSlot, boolean aClearOnFailure) {
+ if (mInputCache != null && mOutputCache != null) {
+ if (GT_Utility.areStacksEqual(aStack, mInputCache)
+ && GT_Utility.areStacksEqual(aSpecialSlot, mOutputCache)) {
+ return true;
+ }
+ }
+ // clear cache if it was invalid
+ if (aClearOnFailure) {
+ mInputCache = null;
+ mOutputCache = null;
+ }
+ return false;
+ }
+
+ private void cacheItem(ItemStack mInputItem, ItemStack mOutputItem) {
+ mOutputCache = mOutputItem.copy();
+ mInputCache = mInputItem.copy();
+ }
+
+ @Override
+ protected boolean allowPutStackValidated(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side,
+ ItemStack aStack) {
+ return hasValidCache(aStack, this.getSpecialSlot(), false) ? true
+ : super.allowPutStackValidated(aBaseMetaTileEntity, aIndex, side, aStack) && hasChiselResults(aStack);
+ }
+
+ // lets make sure the user isn't trying to make something from a block that doesn't have this as a valid target
+ private static boolean canBeMadeFrom(ItemStack from, ItemStack to) {
+ List<ItemStack> results = getItemsForChiseling(from);
+ for (ItemStack s : results) {
+ if (s.getItem() == to.getItem() && s.getItemDamage() == to.getItemDamage()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // lets make sure the user isn't trying to make something from a block that doesn't have this as a valid target
+ private static boolean hasChiselResults(ItemStack from) {
+ List<ItemStack> results = getItemsForChiseling(from);
+ return results.size() > 0;
+ }
+
+ private static List<ItemStack> getItemsForChiseling(ItemStack aStack) {
+ return Carving.chisel.getItemsForChiseling(aStack);
+ }
+
+ private static ItemStack getChiselOutput(ItemStack aInput, ItemStack aTarget) {
+ ItemStack tOutput = null;
+ if (aTarget != null && canBeMadeFrom(aInput, aTarget)) {
+ tOutput = aTarget;
+ } else if (aTarget != null && !canBeMadeFrom(aInput, aTarget)) {
+ tOutput = null;
+ } else {
+ tOutput = getItemsForChiseling(aInput).get(0);
+ }
+ return tOutput;
+ }
+
+ @Override
+ public int checkRecipe() {
+ ItemStack tOutput = null;
+ ItemStack aInput = getInputAt(0);
+ ItemStack aTarget = getSpecialSlot();
+ boolean tIsCached = hasValidCache(aInput, aTarget, true);
+ if (aInput != null && hasChiselResults(aInput) && aInput.stackSize > 0) {
+ tOutput = tIsCached ? mOutputCache.copy() : getChiselOutput(aInput, aTarget);
+ if (tOutput != null) {
+ tOutput = tOutput.copy();
+ tOutput.stackSize = 1;
+ // We can chisel this
+ if (canOutput(tOutput)) {
+ getInputAt(0).stackSize -= 1;
+ calculateOverclockedNess(16, 20);
+ // In case recipe is too OP for that machine
+ if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) {
+ return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS;
+ }
+ if (!tIsCached) {
+ cacheItem(ItemUtils.getSimpleStack(aInput, 1), ItemUtils.getSimpleStack(tOutput, 1));
+ }
+ this.mOutputItems[0] = tOutput.copy();
+ return FOUND_AND_SUCCESSFULLY_USED_RECIPE;
+ } else {
+ mOutputBlocked++;
+ return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS;
+ }
+ }
+ }
+ return DID_NOT_FIND_RECIPE;
+ }
+
+ @Override
+ public boolean useModularUI() {
+ return true;
+ }
+
+ private static final FallbackableUITexture progressBarTexture = GT_UITextures
+ .fallbackableProgressbar("auto_chisel", GT_UITextures.PROGRESSBAR_COMPRESS);
+
+ @Override
+ protected BasicUIProperties getUIProperties() {
+ return super.getUIProperties().toBuilder()
+ .progressBarTexture(progressBarTexture)
+ .build();
+ }
+
+ @Override
+ protected SlotWidget createItemInputSlot(int index, IDrawable[] backgrounds, Pos2d pos) {
+ return (SlotWidget) super.createItemInputSlot(index, backgrounds, pos)
+ .setBackground(getGUITextureSet().getItemSlot(), GT_UITextures.OVERLAY_SLOT_COMPRESSOR);
+ }
+
+ @Override
+ protected SlotWidget createSpecialSlot(IDrawable[] backgrounds, Pos2d pos, BasicUIProperties uiProperties) {
+ return (SlotWidget) super.createSpecialSlot(backgrounds, pos, uiProperties)
+ .setGTTooltip(() -> mTooltipCache.getData("GTPP.machines.chisel_slot.tooltip"));
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GregtechMetaWirelessCharger.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GregtechMetaWirelessCharger.java
new file mode 100644
index 0000000000..b1289958a9
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/basic/GregtechMetaWirelessCharger.java
@@ -0,0 +1,672 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.basic;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import gregtech.api.enums.GT_Values;
+import gregtech.api.enums.Textures;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.metatileentity.BaseMetaTileEntity;
+import gregtech.api.objects.GT_RenderedTexture;
+import gtPlusPlus.api.objects.minecraft.BlockPos;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.minecraft.EntityUtils;
+import gtPlusPlus.core.util.minecraft.PlayerUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMetaTileEntity;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+import gtPlusPlus.xmod.gregtech.common.helpers.ChargingHelper;
+
+public class GregtechMetaWirelessCharger extends GregtechMetaTileEntity {
+
+ private int mCurrentDimension = 0;
+ public int mMode = 0;
+ public boolean mLocked = true;
+
+ public GregtechMetaWirelessCharger(final int aID, final String aName, final String aNameRegional, final int aTier,
+ final String aDescription, final int aSlotCount) {
+ super(aID, aName, aNameRegional, aTier, aSlotCount, aDescription);
+ }
+
+ public GregtechMetaWirelessCharger(final String aName, final int aTier, final String aDescription,
+ final ITexture[][][] aTextures, final int aSlotCount) {
+ super(aName, aTier, aSlotCount, aDescription, aTextures);
+ }
+
+ @Override
+ public String[] getDescription() {
+ return new String[] { this.mDescription, "Can be locked to the owner by sneaking with a screwdriver",
+ "Can also be locked with a lock upgrade", "", "3 Modes, Long-Range, Local and Mixed.",
+ "Long-Range: Can supply 2A of power to a single player up to " + (GT_Values.V[this.mTier] * 4) + "m away.",
+ "Local: Can supply several Amps to each player within " + this.mTier * 20 + "m.",
+ "Mixed: Provides both 2A of long range and 1A per player locally.",
+ "Mixed mode is more conservative of power and as a result only",
+ "Gets half the distances each singular mode gets.", CORE.GT_Tooltip.get() };
+ }
+
+ public int getTier() {
+ return this.mTier;
+ }
+
+ public int getMode() {
+ return this.mMode;
+ }
+
+ public int getDimensionID() {
+ return this.mCurrentDimension;
+ }
+
+ public Map<String, UUID> getLocalMap() {
+ return this.mLocalChargingMap;
+ }
+
+ public Map<String, UUID> getLongRangeMap() {
+ return this.mWirelessChargingMap;
+ }
+
+ @Override
+ public ITexture[][][] getTextureSet(final ITexture[] aTextures) {
+ final ITexture[][][] rTextures = new ITexture[10][17][];
+ for (byte i = -1; i < 16; i++) {
+ rTextures[0][i + 1] = this.getFront(i);
+ rTextures[1][i + 1] = this.getBack(i);
+ rTextures[2][i + 1] = this.getBottom(i);
+ rTextures[3][i + 1] = this.getTop(i);
+ rTextures[4][i + 1] = this.getSides(i);
+ rTextures[5][i + 1] = this.getFrontActive(i);
+ rTextures[6][i + 1] = this.getBackActive(i);
+ rTextures[7][i + 1] = this.getBottomActive(i);
+ rTextures[8][i + 1] = this.getTopActive(i);
+ rTextures[9][i + 1] = this.getSidesActive(i);
+ }
+ return rTextures;
+ }
+
+ @Override
+ public ITexture[] getTexture(final IGregTechTileEntity aBaseMetaTileEntity, final ForgeDirection side,
+ final ForgeDirection facing, final int aColorIndex, final boolean aActive, final boolean aRedstone) {
+ return this.mTextures[(aActive ? 5 : 0) + (side == facing ? 0
+ : side == facing.getOpposite() ? 1
+ : side == ForgeDirection.DOWN ? 2 : side == ForgeDirection.UP ? 3 : 4)][aColorIndex + 1];
+ }
+
+ public ITexture[] getFront(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Screen_2) };
+ }
+
+ public ITexture[] getBack(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ public ITexture[] getBottom(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ public ITexture[] getTop(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ public ITexture[] getSides(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ public ITexture[] getFrontActive(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Screen_2) };
+ }
+
+ public ITexture[] getBackActive(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ public ITexture[] getBottomActive(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ public ITexture[] getTopActive(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ public ITexture[] getSidesActive(final byte aColor) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[this.mTier][aColor + 1],
+ new GT_RenderedTexture(TexturesGtBlock.Casing_Machine_Simple_Bottom) };
+ }
+
+ @Override
+ public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+
+ if (aPlayer.isSneaking()) {
+ mLocked = !mLocked;
+ PlayerUtils.messagePlayer(aPlayer, mLocked ? "Locked to owner." : "Unlocked.");
+ return;
+ }
+
+ mWirelessChargingMap.clear();
+ mLocalChargingMap.clear();
+ if (!this.getBaseMetaTileEntity()
+ .getWorld().playerEntities.isEmpty()) {
+ for (Object mTempPlayer : this.getBaseMetaTileEntity()
+ .getWorld().playerEntities) {
+ if (mTempPlayer instanceof EntityPlayer || mTempPlayer instanceof EntityPlayerMP) {
+ EntityPlayer mTemp = (EntityPlayer) mTempPlayer;
+ ChargingHelper.removeValidPlayer(mTemp, this);
+ }
+ }
+ }
+
+ if (this.mMode >= 2) {
+ this.mMode = 0;
+ } else {
+ this.mMode++;
+ }
+ if (this.mMode == 0) {
+ PlayerUtils.messagePlayer(aPlayer, "Now in Long-Range Charge Mode.");
+ } else if (this.mMode == 1) {
+ PlayerUtils.messagePlayer(aPlayer, "Now in Local Charge Mode.");
+ } else {
+ PlayerUtils.messagePlayer(aPlayer, "Now in Mixed Charge Mode.");
+ }
+ super.onScrewdriverRightClick(side, aPlayer, aX, aY, aZ);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaWirelessCharger(
+ this.mName,
+ this.mTier,
+ this.mDescription,
+ this.mTextures,
+ this.mInventory.length);
+ }
+
+ @Override
+ public boolean isSimpleMachine() {
+ return false;
+ }
+
+ @Override
+ public boolean isElectric() {
+ return true;
+ }
+
+ @Override
+ public boolean isValidSlot(final int aIndex) {
+ return true;
+ }
+
+ @Override
+ public boolean isFacingValid(final ForgeDirection facing) {
+ return true;
+ }
+
+ @Override
+ public boolean isEnetInput() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnetOutput() {
+ return false;
+ }
+
+ @Override
+ public boolean isInputFacing(final ForgeDirection side) {
+ return side != this.getBaseMetaTileEntity()
+ .getFrontFacing();
+ }
+
+ @Override
+ public boolean isOutputFacing(final ForgeDirection side) {
+ return side == this.getBaseMetaTileEntity()
+ .getFrontFacing();
+ }
+
+ @Override
+ public boolean isTeleporterCompatible() {
+ return false;
+ }
+
+ @Override
+ public long getMinimumStoredEU() {
+ return 0;
+ }
+
+ @Override
+ public long maxEUStore() {
+ return GT_Values.V[this.mTier] * 128;
+ }
+
+ @Override
+ public int getCapacity() {
+ return (int) (GT_Values.V[this.mTier] * 32);
+ }
+
+ @Override
+ public long maxEUInput() {
+ return GT_Values.V[this.mTier];
+ }
+
+ @Override
+ public long maxEUOutput() {
+ return 0;
+ }
+
+ @Override
+ public long maxAmperesIn() {
+ if (this.mMode == 0) {
+ return 2;
+ } else if (this.mMode == 1) {
+ return this.mLocalChargingMap.size() * 8;
+ } else {
+ return ((this.mLocalChargingMap.size() * 4) + this.mWirelessChargingMap.size());
+ }
+ }
+
+ @Override
+ public long maxAmperesOut() {
+ return 0;
+ }
+
+ @Override
+ public int rechargerSlotStartIndex() {
+ return 0;
+ }
+
+ @Override
+ public int dechargerSlotStartIndex() {
+ return 0;
+ }
+
+ @Override
+ public int rechargerSlotCount() {
+ return 0;
+ }
+
+ @Override
+ public int dechargerSlotCount() {
+ return 0;
+ }
+
+ @Override
+ public int getProgresstime() {
+ return (int) this.getBaseMetaTileEntity()
+ .getUniversalEnergyStored();
+ }
+
+ @Override
+ public int maxProgresstime() {
+ return (int) this.getBaseMetaTileEntity()
+ .getUniversalEnergyCapacity();
+ }
+
+ @Override
+ public boolean isAccessAllowed(final EntityPlayer aPlayer) {
+ return true;
+ }
+
+ @Override
+ public boolean onRightclick(final IGregTechTileEntity aBaseMetaTileEntity, final EntityPlayer aPlayer) {
+ if (aBaseMetaTileEntity.isClientSide()) {
+ return true;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean allowPullStack(final IGregTechTileEntity aBaseMetaTileEntity, final int aIndex,
+ final ForgeDirection side, final ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public boolean allowPutStack(final IGregTechTileEntity aBaseMetaTileEntity, final int aIndex,
+ final ForgeDirection side, final ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public String[] getInfoData() {
+ return new String[] { this.getLocalName() };
+ }
+
+ @Override
+ public boolean isGivingInformation() {
+ return true;
+ }
+
+ @Override
+ public int[] getAccessibleSlotsFromSide(final int p_94128_1_) {
+ return new int[] {};
+ }
+
+ @Override
+ public boolean canInsertItem(final int p_102007_1_, final ItemStack p_102007_2_, final int p_102007_3_) {
+ return false;
+ }
+
+ @Override
+ public boolean canExtractItem(final int p_102008_1_, final ItemStack p_102008_2_, final int p_102008_3_) {
+ return false;
+ }
+
+ @Override
+ public int getSizeInventory() {
+ return 0;
+ }
+
+ @Override
+ public ItemStack getStackInSlot(final int p_70301_1_) {
+ return null;
+ }
+
+ @Override
+ public ItemStack decrStackSize(final int p_70298_1_, final int p_70298_2_) {
+ return null;
+ }
+
+ @Override
+ public ItemStack getStackInSlotOnClosing(final int p_70304_1_) {
+ return null;
+ }
+
+ @Override
+ public void setInventorySlotContents(final int p_70299_1_, final ItemStack p_70299_2_) {}
+
+ @Override
+ public String getInventoryName() {
+ return null;
+ }
+
+ @Override
+ public boolean hasCustomInventoryName() {
+ return false;
+ }
+
+ @Override
+ public int getInventoryStackLimit() {
+ return 0;
+ }
+
+ @Override
+ public boolean isUseableByPlayer(final EntityPlayer p_70300_1_) {
+ return false;
+ }
+
+ @Override
+ public void openInventory() {}
+
+ @Override
+ public void closeInventory() {}
+
+ @Override
+ public boolean isItemValidForSlot(final int p_94041_1_, final ItemStack p_94041_2_) {
+ return false;
+ }
+
+ @Override
+ public boolean isOverclockerUpgradable() {
+ return false;
+ }
+
+ @Override
+ public boolean isTransformerUpgradable() {
+ return false;
+ }
+
+ @Override
+ public void saveNBTData(final NBTTagCompound aNBT) {
+ aNBT.setBoolean("mLocked", this.mLocked);
+ aNBT.setInteger("mMode", this.mMode);
+ aNBT.setInteger("mCurrentDimension", this.mCurrentDimension);
+ }
+
+ @Override
+ public void loadNBTData(final NBTTagCompound aNBT) {
+ this.mLocked = aNBT.getBoolean("mLocked");
+ this.mMode = aNBT.getInteger("mMode");
+ this.mCurrentDimension = aNBT.getInteger("mCurrentDimension");
+ }
+
+ @Override
+ public void onFirstTick(final IGregTechTileEntity aBaseMetaTileEntity) {
+ super.onFirstTick(aBaseMetaTileEntity);
+ }
+
+ private Map<String, UUID> mWirelessChargingMap = new HashMap<>();
+ private Map<String, UUID> mLocalChargingMap = new HashMap<>();
+
+ private boolean isValidPlayer(EntityPlayer aPlayer) {
+ BaseMetaTileEntity aTile = (BaseMetaTileEntity) this.getBaseMetaTileEntity();
+ if (mLocked || (aTile != null && aTile.privateAccess())) {
+ if (aPlayer.getUniqueID()
+ .equals(getBaseMetaTileEntity().getOwnerUuid())) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void onPostTick(final IGregTechTileEntity aBaseMetaTileEntity, final long aTick) {
+ super.onPostTick(aBaseMetaTileEntity, aTick);
+ if (this.getBaseMetaTileEntity()
+ .isServerSide()) {
+
+ if (this.mCurrentDimension != aBaseMetaTileEntity.getWorld().provider.dimensionId) {
+ this.mCurrentDimension = aBaseMetaTileEntity.getWorld().provider.dimensionId;
+ }
+
+ if (aTick % 20 == 0) {
+ boolean mHasBeenMapped = this.equals(ChargingHelper.getEntry(getTileEntityPosition()));
+ if (!mHasBeenMapped) {
+ mHasBeenMapped = ChargingHelper.addEntry(getTileEntityPosition(), this);
+ }
+
+ if (mHasBeenMapped && !aBaseMetaTileEntity.getWorld().playerEntities.isEmpty()) {
+ for (Object mTempPlayer : aBaseMetaTileEntity.getWorld().playerEntities) {
+ if (mTempPlayer instanceof EntityPlayer || mTempPlayer instanceof EntityPlayerMP) {
+ EntityPlayer mTemp = (EntityPlayer) mTempPlayer;
+
+ if (this.mMode == 1 || this.mMode == 2) {
+ int tempRange = (this.mMode == 1 ? this.mTier * 20 : this.mTier * 10);
+ if (getDistanceBetweenTwoPositions(getTileEntityPosition(), getPositionOfEntity(mTemp))
+ < tempRange) {
+ if (isValidPlayer(mTemp)
+ && !mLocalChargingMap.containsKey(mTemp.getDisplayName())) {
+ mLocalChargingMap.put(mTemp.getDisplayName(), mTemp.getPersistentID());
+ ChargingHelper.addValidPlayer(mTemp, this);
+ // PlayerUtils.messagePlayer(mTemp, "You have entered charging range.
+ // ["+tempRange+"m - Local].");
+ }
+ } else {
+ if (mLocalChargingMap.containsKey(mTemp.getDisplayName())) {
+ if (mLocalChargingMap.remove(mTemp.getDisplayName()) != null) {
+ // PlayerUtils.messagePlayer(mTemp, "You have left charging range.
+ // ["+tempRange+"m - Local].");
+ ChargingHelper.removeValidPlayer(mTemp, this);
+ }
+ }
+ }
+ }
+ if (this.mMode == 0 || this.mMode == 2) {
+ int tempRange = (int) (this.mMode == 0 ? 4 * GT_Values.V[this.mTier]
+ : 2 * GT_Values.V[this.mTier]);
+ if (getDistanceBetweenTwoPositions(getTileEntityPosition(), getPositionOfEntity(mTemp))
+ <= tempRange) {
+ if (!mWirelessChargingMap.containsKey(mTemp.getDisplayName())) {
+ if (isValidPlayer(mTemp)) {
+ mWirelessChargingMap.put(mTemp.getDisplayName(), mTemp.getPersistentID());
+ ChargingHelper.addValidPlayer(mTemp, this);
+ PlayerUtils.messagePlayer(
+ mTemp,
+ "You have entered charging range. [" + tempRange + "m - Long-Range].");
+ }
+ }
+ } else {
+ if (mWirelessChargingMap.containsKey(mTemp.getDisplayName())) {
+ if (mWirelessChargingMap.remove(mTemp.getDisplayName()) != null) {
+ PlayerUtils.messagePlayer(
+ mTemp,
+ "You have left charging range. [" + tempRange + "m - Long Range].");
+ ChargingHelper.removeValidPlayer(mTemp, this);
+ }
+ }
+ }
+ }
+ /*
+ * if (this.mMode == 0 || this.mMode == 2){ int tempRange = (int) (this.mMode == 0 ?
+ * 4*GT_Values.V[this.mTier] : 2*GT_Values.V[this.mTier]); if
+ * (getDistanceBetweenTwoPositions(getTileEntityPosition(), getPositionOfEntity(mTemp)) <
+ * tempRange){ if (!mWirelessChargingMap.containsKey(mTemp)){
+ * mWirelessChargingMap.put(mTemp, mTemp.getPersistentID());
+ * PlayerUtils.messagePlayer(mTemp, "You have entered charging range. ["+tempRange+"m].");
+ * ChargingHelper.addValidPlayer(mTemp, this); } } else { if
+ * (mWirelessChargingMap.containsKey(mTemp)){ if (mWirelessChargingMap.remove(mTemp) !=
+ * null){ PlayerUtils.messagePlayer(mTemp,
+ * "You have left charging range. ["+tempRange+"m].");
+ * ChargingHelper.removeValidPlayer(mTemp, this); } } } }
+ */
+
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public BlockPos getTileEntityPosition() {
+ return new BlockPos(
+ this.getBaseMetaTileEntity()
+ .getXCoord(),
+ this.getBaseMetaTileEntity()
+ .getYCoord(),
+ this.getBaseMetaTileEntity()
+ .getZCoord(),
+ this.getBaseMetaTileEntity()
+ .getWorld());
+ }
+
+ public BlockPos getPositionOfEntity(Entity mEntity) {
+ if (mEntity == null) {
+ return null;
+ }
+ return EntityUtils.findBlockPosUnderEntity(mEntity);
+ }
+
+ public double getDistanceBetweenTwoPositions(BlockPos objectA, BlockPos objectB) {
+ if (objectA == null || objectB == null) {
+ return 0f;
+ }
+ int[] objectArray1 = new int[] { objectA.xPos, objectA.yPos, objectA.zPos };
+ int[] objectArray2 = new int[] { objectB.xPos, objectB.yPos, objectB.zPos };
+
+ final double distance = Math.sqrt(
+ (objectArray2[0] - objectArray1[0]) * (objectArray2[0] - objectArray1[0])
+ + (objectArray2[1] - objectArray1[1]) * (objectArray2[1] - objectArray1[1])
+ + (objectArray2[2] - objectArray1[2]) * (objectArray2[2] - objectArray1[2]));
+ return distance;
+ }
+
+ @Override
+ public void onRemoval() {
+
+ ChargingHelper.removeEntry(getTileEntityPosition(), this);
+
+ mWirelessChargingMap.clear();
+ mLocalChargingMap.clear();
+ if (!this.getBaseMetaTileEntity()
+ .getWorld().playerEntities.isEmpty()) {
+ for (Object mTempPlayer : this.getBaseMetaTileEntity()
+ .getWorld().playerEntities) {
+ if (mTempPlayer instanceof EntityPlayer || mTempPlayer instanceof EntityPlayerMP) {
+ EntityPlayer mTemp = (EntityPlayer) mTempPlayer;
+ ChargingHelper.removeValidPlayer(mTemp, this);
+ }
+ }
+ }
+
+ super.onRemoval();
+ }
+
+ @Override
+ public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer, ForgeDirection side,
+ float aX, float aY, float aZ) {
+
+ int tempRange;
+
+ if (this.mMode == 0 || this.mMode == 2) {
+ tempRange = (int) (this.mMode == 0 ? 4 * GT_Values.V[this.mTier] : 2 * GT_Values.V[this.mTier]);
+ } else {
+ tempRange = this.mMode == 1 ? this.mTier * 20 : this.mTier * 10;
+ }
+
+ if (this.mMode == 2) {
+ PlayerUtils
+ .messagePlayer(aPlayer, "Mixed Mode | Local: " + this.mTier * 10 + "m | Long: " + tempRange + "m");
+ PlayerUtils.messagePlayer(aPlayer, "Players with access:");
+ for (String name : this.getLocalMap()
+ .keySet()) {
+ PlayerUtils.messagePlayer(aPlayer, "Local: " + name);
+ }
+ for (String name : this.getLongRangeMap()
+ .keySet()) {
+ PlayerUtils.messagePlayer(aPlayer, "Long: " + name);
+ }
+ } else if (this.mMode == 1) {
+ PlayerUtils.messagePlayer(aPlayer, "Local Mode: " + this.mTier * 20 + "m");
+ PlayerUtils.messagePlayer(aPlayer, "Players with access:");
+ for (String name : this.getLocalMap()
+ .keySet()) {
+ PlayerUtils.messagePlayer(aPlayer, "" + name);
+ }
+
+ } else {
+ PlayerUtils.messagePlayer(aPlayer, "Long-range Mode: " + tempRange + "m");
+ PlayerUtils.messagePlayer(aPlayer, "Players with access:");
+ for (String name : this.getLongRangeMap()
+ .keySet()) {
+ PlayerUtils.messagePlayer(aPlayer, "" + name);
+ }
+ }
+
+ return super.onRightclick(aBaseMetaTileEntity, aPlayer, side, aX, aY, aZ);
+ }
+
+ @Override
+ public void onServerStart() {
+ mWirelessChargingMap.clear();
+ mLocalChargingMap.clear();
+ super.onServerStart();
+ }
+
+ @Override
+ public void onExplosion() {
+ ChargingHelper.removeEntry(getTileEntityPosition(), this);
+ super.onExplosion();
+ }
+
+ @Override
+ public void doExplosion(long aExplosionPower) {
+ ChargingHelper.removeEntry(getTileEntityPosition(), this);
+ super.doExplosion(aExplosionPower);
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/misc/GMTE_AmazonPackager.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/misc/GMTE_AmazonPackager.java
new file mode 100644
index 0000000000..0e71c3b9b1
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/misc/GMTE_AmazonPackager.java
@@ -0,0 +1,168 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.misc;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import net.minecraft.item.ItemStack;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GMTE_AmazonPackager extends GregtechMeta_MultiBlockBase<GMTE_AmazonPackager>
+ implements ISurvivalConstructable {
+
+ private int mCasing;
+
+ private static IStructureDefinition<GMTE_AmazonPackager> STRUCTURE_DEFINITION = null;
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GMTE_AmazonPackager(mName);
+ }
+
+ public GMTE_AmazonPackager(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GMTE_AmazonPackager(String aName) {
+ super(aName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Packager";
+ }
+
+ @Override
+ public IStructureDefinition<GMTE_AmazonPackager> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GMTE_AmazonPackager>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC" }, { "C~C", "C-C", "CCC" }, { "CCC", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GMTE_AmazonPackager.class)
+ .atLeast(InputBus, OutputBus, Maintenance, Energy, Muffler)
+ .casingIndex(TAE.getIndexFromPage(2, 9))
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings3Misc, 9))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Amazon Warehouse")
+ .addInfo("This Multiblock is used for EXTREME packaging requirements")
+ .addInfo("Dust Schematics are inserted into the input busses")
+ .addInfo("If inserted into the controller, it is shared across all busses")
+ .addInfo("1x, 2x, 3x & Other Schematics are to be placed into the controller GUI slot")
+ .addInfo("500% faster than using single block machines of the same voltage")
+ .addInfo("Only uses 75% of the EU/t normally required")
+ .addInfo("Processes 16 items per voltage tier")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 3, 3, true)
+ .addController("Front center")
+ .addCasingInfoMin("Supply Depot Casings", 10, false)
+ .addInputBus("Any casing", 1)
+ .addOutputBus("Any casing", 1)
+ .addEnergyHatch("Any casing", 1)
+ .addMaintenanceHatch("Any casing", 1)
+ .addMufflerHatch("Any casing", 1)
+ .toolTipFinisher("GT++");
+ return tt;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return TAE.getIndexFromPage(2, 9);
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return RecipeMaps.packagerRecipes;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic().setSpeedBonus(1F / 6F)
+ .setEuModifier(0.75F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ return checkPiece(mName, 1, 1, 0) && mCasing >= 10 && checkHatch();
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack p0) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(ItemStack arg0) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiPackager;
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return (16 * GT_Utility.getTier(this.getMaxInputVoltage()));
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 1, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean supportsInputSeparation() {
+ return true;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialAlloySmelter.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialAlloySmelter.java
new file mode 100644
index 0000000000..e5d138dfda
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialAlloySmelter.java
@@ -0,0 +1,223 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+import static gregtech.api.util.GT_StructureUtility.ofCoil;
+
+import net.minecraft.item.ItemStack;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.HeatingCoilLevel;
+import gregtech.api.enums.TAE;
+import gregtech.api.enums.Textures;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_OverclockCalculator;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+
+public class GregtechMetaTileEntity_IndustrialAlloySmelter extends
+ GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialAlloySmelter> implements ISurvivalConstructable {
+
+ public static int CASING_TEXTURE_ID;
+ private HeatingCoilLevel mHeatingCapacity;
+ private int mLevel = 0;
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialAlloySmelter> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_IndustrialAlloySmelter(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ CASING_TEXTURE_ID = TAE.getIndexFromPage(2, 1);
+ }
+
+ public GregtechMetaTileEntity_IndustrialAlloySmelter(String aName) {
+ super(aName);
+ CASING_TEXTURE_ID = TAE.getIndexFromPage(2, 1);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IndustrialAlloySmelter(this.mName);
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return Textures.BlockIcons.OVERLAY_FRONT_MULTI_SMELTER_ACTIVE;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return Textures.BlockIcons.OVERLAY_FRONT_MULTI_SMELTER;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return CASING_TEXTURE_ID;
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return RecipeMaps.alloySmelterRecipes;
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialAlloySmelter;
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Alloy Smelter";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Industrial Alloy Smelter")
+ .addInfo("Gains one parallel per voltage tier")
+ .addInfo("Gains one multiplier per coil tier")
+ .addInfo("Parallel = Tier * Coil Tier")
+ .addInfo("Gains 5% speed bonus per coil tier")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 5, 3, true)
+ .addController("Bottom center")
+ .addCasingInfoMin("Inconel Reinforced Casings", 8, false)
+ .addOtherStructurePart("Integral Encasement V", "Middle Layer")
+ .addOtherStructurePart("Heating Coils", "Above and below Integral Encasements")
+ .addInputBus("Any Inconel Reinforced Casing", 1)
+ .addOutputBus("Any Inconel Reinforced Casing", 1)
+ .addEnergyHatch("Any Inconel Reinforced Casing", 1)
+ .addMaintenanceHatch("Any Inconel Reinforced Casing", 1)
+ .addMufflerHatch("Any Inconel Reinforced Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialAlloySmelter> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialAlloySmelter>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC" }, { "HHH", "H-H", "HHH" }, { "VVV", "V-V", "VVV" },
+ { "HHH", "H-H", "HHH" }, { "C~C", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialAlloySmelter.class)
+ .atLeast(InputBus, OutputBus, Maintenance, Energy, Muffler)
+ .casingIndex(CASING_TEXTURE_ID)
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings3Misc, 1))))
+ .addElement(
+ 'H',
+ ofCoil(
+ GregtechMetaTileEntity_IndustrialAlloySmelter::setCoilLevel,
+ GregtechMetaTileEntity_IndustrialAlloySmelter::getCoilLevel))
+ .addElement('V', ofBlock(ModBlocks.blockCasingsTieredGTPP, 4))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 4, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 4, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ mLevel = 0;
+ setCoilLevel(HeatingCoilLevel.None);
+ return checkPiece(mName, 1, 4, 0) && mCasing >= 8
+ && getCoilLevel() != HeatingCoilLevel.None
+ && (mLevel = getCoilLevel().getTier() + 1) > 0
+ && checkHatch();
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return (this.mLevel * GT_Utility.getTier(this.getMaxInputVoltage()));
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic() {
+
+ @NotNull
+ @Override
+ protected GT_OverclockCalculator createOverclockCalculator(@NotNull GT_Recipe recipe) {
+ return super.createOverclockCalculator(recipe).setSpeedBoost(100F / (100F + 5F * mLevel))
+ .setHeatOC(true)
+ .setRecipeHeat(0)
+ // Need to multiply by 2 because heat OC is done only once every 1800 and this one does it once
+ // every
+ // 900
+ .setMachineHeat((int) (getCoilLevel().getHeat() * 2));
+ }
+ }.setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ public HeatingCoilLevel getCoilLevel() {
+ return mHeatingCapacity;
+ }
+
+ public void setCoilLevel(HeatingCoilLevel aCoilLevel) {
+ mHeatingCapacity = aCoilLevel;
+ }
+
+ @Override
+ public boolean isInputSeparationEnabled() {
+ return true;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialArcFurnace.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialArcFurnace.java
new file mode 100644
index 0000000000..c27422fb93
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialArcFurnace.java
@@ -0,0 +1,337 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import javax.annotation.Nonnull;
+
+import net.minecraft.block.Block;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.SoundResource;
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.minecraft.PlayerUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_IndustrialArcFurnace
+ extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialArcFurnace> implements ISurvivalConstructable {
+
+ // 862
+ private static final int mCasingTextureID = TAE.getIndexFromPage(3, 3);
+ public static String mCasingName = "Tempered Arc Furnace Casing";
+ private boolean mPlasmaMode = false;
+ private int mSize = 0;
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialArcFurnace> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_IndustrialArcFurnace(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_IndustrialArcFurnace(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IndustrialArcFurnace(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "(Plasma/Electric) Arc Furnace";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for Industrial Arc Furnace")
+ .addInfo("250% faster than using single block machines of the same voltage")
+ .addInfo("Processes 8 items per voltage tier * W/L")
+ .addInfo("Right-click controller with a Screwdriver to change modes")
+ .addInfo("Max Size required to process Plasma recipes")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .addController("Top center")
+ .addStructureInfo("Size: nxnx3 [WxHxL] (Hollow)")
+ .addStructureInfo("n can be 3, 5 or 7")
+ .addCasingInfoMin(mCasingName, 10, false)
+ .addInputBus("Any Casing", 1)
+ .addOutputBus("Any Casing", 1)
+ .addInputHatch("Any Casing", 1)
+ .addOutputHatch("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ /**
+ * The front part of multi. Used to determine the tier, or in other words, determine the size of multi.
+ */
+ private static final String STRUCTURE_PIECE_FRONT = "front";
+ /**
+ * The rest part of multi.
+ */
+ private static final String STRUCTURE_PIECE_REST = "rest";
+ private static final int MAX_TIER = 3;
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialArcFurnace> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialArcFurnace>builder()
+ .addShape(STRUCTURE_PIECE_FRONT + 1, new String[][] { { "CCC", "C~C", "CCC" } })
+ .addShape(STRUCTURE_PIECE_FRONT + 2, new String[][] { { "CCCCC", "C C", "C C", "C C", "CCCCC" } })
+ .addShape(
+ STRUCTURE_PIECE_FRONT + 3,
+ new String[][] { { "CCCCCCC", "C C", "C C", "C C", "C C", "C C", "CCCCCCC" }, })
+ .addShape(STRUCTURE_PIECE_REST + 1, new String[][] { { "CCC", "C-C", "CCC" }, { "CCC", "CCC", "CCC" } })
+ .addShape(
+ STRUCTURE_PIECE_REST + 2,
+ new String[][] { { "CCCCC", "C---C", "C---C", "C---C", "CCCCC" },
+ { "CCCCC", "CCCCC", "CCCCC", "CCCCC", "CCCCC" } })
+ .addShape(
+ STRUCTURE_PIECE_REST + 3,
+ new String[][] { { "CCCCCCC", "C-----C", "C-----C", "C-----C", "C-----C", "C-----C", "CCCCCCC" },
+ { "CCCCCCC", "CCCCCCC", "CCCCCCC", "CCCCCCC", "CCCCCCC", "CCCCCCC", "CCCCCCC" }, })
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialArcFurnace.class)
+ .atLeast(InputBus, InputHatch, OutputBus, OutputHatch, Maintenance, Energy, Muffler)
+ .casingIndex(getCasingTextureIndex())
+ .dot(1)
+ .allowOnly(ForgeDirection.NORTH)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings4Misc, 3))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ private int getTierFromHint(ItemStack stackSize) {
+ if (stackSize.stackSize <= 0 || stackSize.stackSize >= MAX_TIER) {
+ return MAX_TIER;
+ }
+ return stackSize.stackSize;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ int maxTier = getTierFromHint(stackSize);
+ for (int tier = 1; tier <= maxTier; tier++) {
+ buildPiece(STRUCTURE_PIECE_FRONT + tier, stackSize, hintsOnly, tier, tier, 0);
+ }
+ buildPiece(STRUCTURE_PIECE_REST + maxTier, stackSize, hintsOnly, maxTier, maxTier, -1);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ int maxTier = getTierFromHint(stackSize);
+ int built;
+ for (int tier = 1; tier <= maxTier; tier++) {
+ built = survivialBuildPiece(
+ STRUCTURE_PIECE_FRONT + tier,
+ stackSize,
+ tier,
+ tier,
+ 0,
+ elementBudget,
+ env,
+ false,
+ true);
+ if (built >= 0) return built;
+ }
+
+ return survivialBuildPiece(
+ STRUCTURE_PIECE_REST + maxTier,
+ stackSize,
+ maxTier,
+ maxTier,
+ -1,
+ elementBudget,
+ env,
+ false,
+ true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ mSize = 0;
+ int tier = 0;
+ while (tier < MAX_TIER && checkPiece(STRUCTURE_PIECE_FRONT + (tier + 1), (tier + 1), (tier + 1), 0)) {
+ tier++;
+ }
+ if (tier <= 0) return false;
+ if (checkPiece(STRUCTURE_PIECE_REST + tier, tier, tier, -1)) {
+ mSize = 2 * tier + 1;
+ return mCasing >= 10 && checkHatch();
+ }
+ return false;
+ }
+
+ @Override
+ protected SoundResource getProcessStartSound() {
+ return SoundResource.IC2_MACHINES_ELECTROFURNACE_LOOP;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return mCasingTextureID;
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return mPlasmaMode ? RecipeMaps.plasmaArcFurnaceRecipes : RecipeMaps.arcFurnaceRecipes;
+ }
+
+ @Nonnull
+ @Override
+ public Collection<RecipeMap<?>> getAvailableRecipeMaps() {
+ return Arrays.asList(RecipeMaps.arcFurnaceRecipes, RecipeMaps.plasmaArcFurnaceRecipes);
+ }
+
+ @Override
+ public int getRecipeCatalystPriority() {
+ return -1;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic().setSpeedBonus(1F / 3.5F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return (this.mSize * 8 * GT_Utility.getTier(this.getMaxInputVoltage()));
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialArcFurnace;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ public Block getCasingBlock() {
+ return ModBlocks.blockCasings4Misc;
+ }
+
+ public byte getCasingMeta() {
+ return 3;
+ }
+
+ public byte getCasingTextureIndex() {
+ return (byte) mCasingTextureID;
+ }
+
+ @Override
+ public void onModeChangeByScrewdriver(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+ if (this.mSize > 5) {
+ this.mPlasmaMode = !mPlasmaMode;
+ if (mPlasmaMode) {
+ PlayerUtils.messagePlayer(
+ aPlayer,
+ "[" + EnumChatFormatting.RED
+ + "MODE"
+ + EnumChatFormatting.RESET
+ + "] "
+ + EnumChatFormatting.LIGHT_PURPLE
+ + "Plasma"
+ + EnumChatFormatting.RESET);
+ } else {
+ PlayerUtils.messagePlayer(
+ aPlayer,
+ "[" + EnumChatFormatting.RED
+ + "MODE"
+ + EnumChatFormatting.RESET
+ + "] "
+ + EnumChatFormatting.YELLOW
+ + "Electric"
+ + EnumChatFormatting.RESET);
+ }
+ } else {
+ PlayerUtils.messagePlayer(
+ aPlayer,
+ "[" + EnumChatFormatting.RED
+ + "MODE"
+ + EnumChatFormatting.RESET
+ + "] "
+ + EnumChatFormatting.GRAY
+ + "Cannot change mode, structure not large enough."
+ + EnumChatFormatting.RESET);
+ }
+ mLastRecipe = null;
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ super.saveNBTData(aNBT);
+ aNBT.setBoolean("mPlasmaMode", mPlasmaMode);
+ aNBT.setInteger("mSize", mSize);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ mPlasmaMode = aNBT.getBoolean("mPlasmaMode");
+ mSize = aNBT.getInteger("mSize");
+ }
+
+ @Override
+ public void onMachineBlockUpdate() {
+ mUpdate = 100;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialCentrifuge.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialCentrifuge.java
new file mode 100644
index 0000000000..c04620d4b4
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialCentrifuge.java
@@ -0,0 +1,228 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import net.minecraft.block.Block;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.api.objects.Logger;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.minecraft.PlayerUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock.CustomIcon;
+
+public class GregtechMetaTileEntity_IndustrialCentrifuge
+ extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialCentrifuge> implements ISurvivalConstructable {
+
+ private boolean mIsAnimated;
+ private static final CustomIcon frontFaceActive = new CustomIcon("iconsets/LARGECENTRIFUGE_ACTIVE5");
+ private static final CustomIcon frontFace = new CustomIcon("iconsets/LARGECENTRIFUGE5");
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialCentrifuge> STRUCTURE_DEFINITION = null;
+ // public static double recipesComplete = 0;
+
+ public GregtechMetaTileEntity_IndustrialCentrifuge(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ mIsAnimated = true;
+ }
+
+ public GregtechMetaTileEntity_IndustrialCentrifuge(final String aName) {
+ super(aName);
+ mIsAnimated = true;
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IndustrialCentrifuge(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Centrifuge";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Industrial Centrifuge")
+ .addInfo("125% faster than using single block machines of the same voltage")
+ .addInfo("Disable animations with a screwdriver")
+ .addInfo("Only uses 90% of the EU/t normally required")
+ .addInfo("Processes six items per voltage tier")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 3, 3, true)
+ .addController("Front Center")
+ .addCasingInfoMin("Centrifuge Casings", 6, false)
+ .addInputBus("Any Casing", 1)
+ .addOutputBus("Any Casing", 1)
+ .addInputHatch("Any Casing", 1)
+ .addOutputHatch("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialCentrifuge> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialCentrifuge>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC" }, { "C~C", "C-C", "CCC" }, { "CCC", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialCentrifuge.class)
+ .atLeast(InputBus, OutputBus, Maintenance, Energy, Muffler, InputHatch, OutputHatch)
+ .casingIndex(getCasingTextureIndex())
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasingsMisc, 0))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 1, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ return checkPiece(mName, 1, 1, 0) && mCasing >= 6 && checkHatch();
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ if (usingAnimations()) {
+ return frontFaceActive;
+ } else {
+ return frontFace;
+ }
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return frontFace;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return TAE.GTPP_INDEX(0);
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return GTPPRecipeMaps.centrifugeNonCellRecipes;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic().setEuModifier(0.9F)
+ .setSpeedBonus(1F / 2.25F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return (6 * GT_Utility.getTier(this.getMaxInputVoltage()));
+ }
+
+ public Block getCasingBlock() {
+ return ModBlocks.blockCasingsMisc;
+ }
+
+ public byte getCasingMeta() {
+ return 0;
+ }
+
+ public byte getCasingTextureIndex() {
+ return (byte) TAE.GTPP_INDEX(0);
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialCentrifuge;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public void onModeChangeByScrewdriver(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+ this.mIsAnimated = !mIsAnimated;
+ Logger.INFO("Is Centrifuge animated " + this.mIsAnimated);
+ if (this.mIsAnimated) {
+ PlayerUtils.messagePlayer(aPlayer, "Using Animated Turbine Texture. ");
+ } else {
+ PlayerUtils.messagePlayer(aPlayer, "Using Static Turbine Texture. ");
+ }
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ super.saveNBTData(aNBT);
+ aNBT.setBoolean("mIsAnimated", mIsAnimated);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ if (aNBT.hasKey("mIsAnimated")) {
+ mIsAnimated = aNBT.getBoolean("mIsAnimated");
+ } else {
+ mIsAnimated = true;
+ }
+ }
+
+ public boolean usingAnimations() {
+ // Logger.INFO("Is animated? "+this.mIsAnimated);
+ return this.mIsAnimated;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialChisel.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialChisel.java
new file mode 100644
index 0000000000..a9f18dfce8
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialChisel.java
@@ -0,0 +1,342 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import java.util.List;
+import java.util.stream.Stream;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.minecraft.init.Blocks;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.ResourceLocation;
+import net.minecraftforge.fluids.FluidStack;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.SoundResource;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_InputBus;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.GT_StreamUtil;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.minecraft.ItemUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.GT_MetaTileEntity_ChiselBus;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+import team.chisel.carving.Carving;
+
+public class GregtechMetaTileEntity_IndustrialChisel
+ extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialChisel> implements ISurvivalConstructable {
+
+ private int mCasing;
+
+ private ItemStack target;
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialChisel> STRUCTURE_DEFINITION = null;
+ private ItemStack mInputCache;
+ private ItemStack mOutputCache;
+ private GT_Recipe mCachedRecipe;
+
+ public GregtechMetaTileEntity_IndustrialChisel(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_IndustrialChisel(String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IndustrialChisel(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Chisel";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Factory Grade Auto Chisel")
+ .addInfo("Target block goes in Controller slot for common Input Buses")
+ .addInfo("You can also set a target block in each Chisel Input Bus and use them as an Input Bus")
+ .addInfo("If no target is provided for common buses, the result of the first chisel is used")
+ .addInfo("Speed: +200% | EU Usage: 75% | Parallel: Tier x 16")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 3, 3, true)
+ .addController("Front center")
+ .addCasingInfoMin("Sturdy Printer Casing", 6, false)
+ .addInputBus("Any casing", 1)
+ .addOutputBus("Any casing", 1)
+ .addEnergyHatch("Any casing", 1)
+ .addMaintenanceHatch("Any casing", 1)
+ .addMufflerHatch("Any casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialChisel> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialChisel>builder()
+ .addShape(
+ mName,
+ transpose(
+ // spotless:off
+ new String[][] {
+ { "CCC", "CCC", "CCC" },
+ { "C~C", "C-C", "CCC" },
+ { "CCC", "CCC", "CCC" },
+ }))
+ // spotless:on
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialChisel.class)
+ .atLeast(InputBus, OutputBus, Maintenance, Energy, Muffler)
+ .casingIndex(90)
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings5Misc, 5))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 1, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ return checkPiece(mName, 1, 1, 0) && mCasing >= 6 && checkHatch();
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return 90;
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(ItemStack aStack) {
+ return true;
+ }
+
+ private boolean hasValidCache(ItemStack aStack, ItemStack aSpecialSlot, boolean aClearOnFailure) {
+ if (mInputCache != null && mOutputCache != null && mCachedRecipe != null) {
+ if (GT_Utility.areStacksEqual(aStack, mInputCache)
+ && GT_Utility.areStacksEqual(aSpecialSlot, mOutputCache)) {
+ return true;
+ }
+ }
+ // clear cache if it was invalid
+ if (aClearOnFailure) {
+ mInputCache = null;
+ mOutputCache = null;
+ mCachedRecipe = null;
+ }
+ return false;
+ }
+
+ private void cacheItem(ItemStack aInputItem, ItemStack aOutputItem, GT_Recipe aRecipe) {
+ mInputCache = aInputItem.copy();
+ mOutputCache = aOutputItem.copy();
+ mCachedRecipe = aRecipe;
+ }
+
+ // lets make sure the user isn't trying to make something from a block that doesn't have this as a valid target
+ private static boolean canBeMadeFrom(ItemStack from, ItemStack to) {
+ List<ItemStack> results = getItemsForChiseling(from);
+ for (ItemStack s : results) {
+ if (s.getItem() == to.getItem() && s.getItemDamage() == to.getItemDamage()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // lets make sure the user isn't trying to make something from a block that doesn't have this as a valid target
+ private static boolean hasChiselResults(ItemStack from) {
+ List<ItemStack> results = getItemsForChiseling(from);
+ return results.size() > 0;
+ }
+
+ private static List<ItemStack> getItemsForChiseling(ItemStack aStack) {
+ return Carving.chisel.getItemsForChiseling(aStack);
+ }
+
+ private static ItemStack getChiselOutput(ItemStack aInput, ItemStack aTarget) {
+ ItemStack tOutput;
+ if (aTarget != null && canBeMadeFrom(aInput, aTarget)) {
+ tOutput = aTarget;
+ } else if (aTarget != null && !canBeMadeFrom(aInput, aTarget)) {
+ tOutput = null;
+ } else {
+ tOutput = getItemsForChiseling(aInput).get(0);
+ }
+ return tOutput;
+ }
+
+ private GT_Recipe generateChiselRecipe(ItemStack aInput) {
+ boolean tIsCached = hasValidCache(aInput, this.target, true);
+ if (tIsCached || aInput != null && hasChiselResults(aInput)) {
+ ItemStack tOutput = tIsCached ? mOutputCache.copy() : getChiselOutput(aInput, this.target);
+ if (tOutput != null) {
+ if (mCachedRecipe != null && GT_Utility.areStacksEqual(aInput, mInputCache)
+ && GT_Utility.areStacksEqual(tOutput, mOutputCache)) {
+ return mCachedRecipe;
+ }
+ // We can chisel this
+ GT_Recipe aRecipe = new GT_Recipe(
+ false,
+ new ItemStack[] { ItemUtils.getSimpleStack(aInput, 1) },
+ new ItemStack[] { ItemUtils.getSimpleStack(tOutput, 1) },
+ null,
+ new int[] { 10000 },
+ new FluidStack[] {},
+ new FluidStack[] {},
+ 20,
+ 16,
+ 0);
+
+ // Cache it
+ cacheItem(aInput, tOutput, aRecipe);
+ return aRecipe;
+ }
+ }
+ return null;
+ }
+
+ private GT_Recipe getRecipe() {
+ for (GT_MetaTileEntity_Hatch_InputBus bus : this.mInputBusses) {
+ if (bus instanceof GT_MetaTileEntity_ChiselBus) { // Chisel buses
+ if (bus.mInventory[bus.getSizeInventory() - 1] == null) continue;
+ this.target = bus.mInventory[bus.getSizeInventory() - 1];
+
+ for (int i = bus.getSizeInventory() - 2; i >= 0; i--) {
+ ItemStack itemsInSlot = bus.mInventory[i];
+ if (itemsInSlot != null) {
+ GT_Recipe tRecipe = generateChiselRecipe(itemsInSlot);
+ if (tRecipe != null) {
+ return tRecipe;
+ }
+ }
+ }
+ } else {
+ target = this.getControllerSlot(); // Common buses
+ for (int i = bus.getSizeInventory() - 1; i >= 0; i--) {
+ ItemStack itemsInSlot = bus.mInventory[i];
+ if (itemsInSlot != null) {
+ GT_Recipe tRecipe = generateChiselRecipe(itemsInSlot);
+ if (tRecipe != null) {
+ return tRecipe;
+ }
+ }
+ }
+ }
+
+ }
+ return null;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic() {
+
+ @Nonnull
+ @Override
+ protected Stream<GT_Recipe> findRecipeMatches(@Nullable RecipeMap<?> map) {
+ return GT_StreamUtil.ofNullable(getRecipe());
+ }
+ }.setSpeedBonus(1F / 3F)
+ .setEuModifier(0.75F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ protected void sendStartMultiBlockSoundLoop() {
+ sendLoopStart(PROCESS_START_SOUND_INDEX);
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return (16 * GT_Utility.getTier(this.getMaxInputVoltage()));
+ }
+
+ private static ResourceLocation sChiselSound = null;
+
+ private static ResourceLocation getChiselSound() {
+ if (sChiselSound == null) {
+ sChiselSound = new ResourceLocation(Carving.chisel.getVariationSound(Blocks.stone, 0));
+ }
+ return sChiselSound;
+ }
+
+ @Override
+ public void doSound(byte aIndex, double aX, double aY, double aZ) {
+ switch (aIndex) {
+ case PROCESS_START_SOUND_INDEX -> GT_Utility
+ .doSoundAtClient(getChiselSound(), getTimeBetweenProcessSounds(), 1.0F, 1.0F, aX, aY, aZ);
+ case INTERRUPT_SOUND_INDEX -> GT_Utility
+ .doSoundAtClient(SoundResource.IC2_MACHINES_INTERRUPT_ONE, 100, 1.0F, aX, aY, aZ);
+ }
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialChisel;
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(ItemStack aStack) {
+ return false;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialCokeOven.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialCokeOven.java
new file mode 100644
index 0000000000..b71600e3fd
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialCokeOven.java
@@ -0,0 +1,209 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import net.minecraft.item.ItemStack;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.SoundResource;
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_IndustrialCokeOven
+ extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialCokeOven> implements ISurvivalConstructable {
+
+ private int mLevel = 0;
+ private int mCasing;
+ private int mCasing1;
+ private int mCasing2;
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialCokeOven> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_IndustrialCokeOven(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_IndustrialCokeOven(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IndustrialCokeOven(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Coke Oven";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Processes Logs and Coal into Charcoal and Coal Coke.")
+ .addInfo("Controller Block for the Industrial Coke Oven")
+ .addInfo("Gain 4% energy discount per voltage tier")
+ .addInfo("Process 12x materials with Heat Resistant Casings")
+ .addInfo("Or 24x materials with Heat Proof Casings")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 3, 3, true)
+ .addController("Front middle at bottom")
+ .addCasingInfoMin("Structural Coke Oven Casings", 8, false)
+ .addCasingInfoMin("Heat Resistant/Proof Coke Oven Casings", 8, false)
+ .addInputBus("Any Structural Coke Oven Casing", 1)
+ .addOutputBus("Any Structural Coke Oven Casing", 1)
+ .addInputHatch("Any Structural Coke Oven Casing", 1)
+ .addOutputHatch("Any Structural Coke Oven Casing", 1)
+ .addEnergyHatch("Any Structural Coke Oven Casing", 1)
+ .addMaintenanceHatch("Any Structural Coke Oven Casing", 1)
+ .addMufflerHatch("Any Structural Coke Oven Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialCokeOven> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialCokeOven>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC" }, { "HHH", "H-H", "HHH" }, { "C~C", "CCC", "CCC" }, }))
+ .addShape(
+ mName + "1",
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC" }, { "aaa", "a-a", "aaa" }, { "C~C", "CCC", "CCC" }, }))
+ .addShape(
+ mName + "2",
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC" }, { "bbb", "b-b", "bbb" }, { "C~C", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialCokeOven.class)
+ .atLeast(InputBus, OutputBus, InputHatch, OutputHatch, Maintenance, Energy, Muffler)
+ .casingIndex(TAE.GTPP_INDEX(1))
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasingsMisc, 1))))
+ .addElement(
+ 'H',
+ ofChain(
+ onElementPass(x -> ++x.mCasing1, ofBlock(ModBlocks.blockCasingsMisc, 2)),
+ onElementPass(x -> ++x.mCasing2, ofBlock(ModBlocks.blockCasingsMisc, 3))))
+ .addElement('a', ofBlock(ModBlocks.blockCasingsMisc, 2))
+ .addElement('b', ofBlock(ModBlocks.blockCasingsMisc, 3))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ if (stackSize.stackSize == 1) buildPiece(mName + "1", stackSize, hintsOnly, 1, 2, 0);
+ else buildPiece(mName + "2", stackSize, hintsOnly, 1, 2, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ if (stackSize.stackSize == 1)
+ return survivialBuildPiece(mName + "1", stackSize, 1, 2, 0, elementBudget, env, false, true);
+ else return survivialBuildPiece(mName + "2", stackSize, 1, 2, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ mCasing1 = 0;
+ mCasing2 = 0;
+ mLevel = 0;
+ if (checkPiece(mName, 1, 2, 0)) {
+ if (mCasing1 == 8) mLevel = 1;
+ if (mCasing2 == 8) mLevel = 2;
+ return mLevel > 0 && mCasing >= 8 && checkHatch();
+ }
+ return false;
+ }
+
+ @Override
+ protected SoundResource getProcessStartSound() {
+ return SoundResource.IC2_MACHINES_ELECTROFURNACE_LOOP;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return TAE.GTPP_INDEX(1);
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return GTPPRecipeMaps.cokeOvenRecipes;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic().setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ protected void setupProcessingLogic(ProcessingLogic logic) {
+ super.setupProcessingLogic(logic);
+ logic.setEuModifier((100F - (GT_Utility.getTier(getMaxInputVoltage()) * 4)) / 100F);
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return this.mLevel * 12;
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialCokeOven;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialCuttingMachine.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialCuttingMachine.java
new file mode 100644
index 0000000000..295f195d55
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialCuttingMachine.java
@@ -0,0 +1,230 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import javax.annotation.Nonnull;
+
+import net.minecraft.block.Block;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.minecraft.PlayerUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_IndustrialCuttingMachine extends
+ GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialCuttingMachine> implements ISurvivalConstructable {
+
+ private boolean mCuttingMode = true;
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialCuttingMachine> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_IndustrialCuttingMachine(final int aID, final String aName,
+ final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_IndustrialCuttingMachine(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IndustrialCuttingMachine(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Cutting Machine / Slicing Machine";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Industrial Cutting Factory")
+ .addInfo("200% faster than using single block machines of the same voltage")
+ .addInfo("Only uses 75% of the EU/t normally required")
+ .addInfo("Processes four items per voltage tier")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 3, 5, true)
+ .addController("Front Center")
+ .addCasingInfoMin("Cutting Factory Frames", 14, false)
+ .addInputBus("Any Casing", 1)
+ .addOutputBus("Any Casing", 1)
+ .addInputHatch("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialCuttingMachine> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialCuttingMachine>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC", "CCC", "CCC" }, { "C~C", "C-C", "C-C", "C-C", "CCC" },
+ { "CCC", "CCC", "CCC", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialCuttingMachine.class)
+ .atLeast(InputBus, InputHatch, OutputBus, Maintenance, Energy, Muffler)
+ .casingIndex(getCasingTextureIndex())
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings2Misc, 13))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 1, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ return checkPiece(mName, 1, 1, 0) && mCasing >= 14 && checkHatch();
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return TAE.GTPP_INDEX(29);
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return mCuttingMode ? RecipeMaps.cutterRecipes : RecipeMaps.slicerRecipes;
+ }
+
+ @Nonnull
+ @Override
+ public Collection<RecipeMap<?>> getAvailableRecipeMaps() {
+ return Arrays.asList(RecipeMaps.cutterRecipes, RecipeMaps.slicerRecipes);
+ }
+
+ @Override
+ public int getRecipeCatalystPriority() {
+ return -1;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic().setSpeedBonus(1F / 3F)
+ .setEuModifier(0.75F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return (4 * GT_Utility.getTier(this.getMaxInputVoltage()));
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialCuttingMachine;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public boolean isInputSeparationEnabled() {
+ return true;
+ }
+
+ public Block getCasingBlock() {
+ return ModBlocks.blockCasings2Misc;
+ }
+
+ public byte getCasingMeta() {
+ return 13;
+ }
+
+ public byte getCasingTextureIndex() {
+ return (byte) TAE.GTPP_INDEX(29);
+ }
+
+ @Override
+ public void onModeChangeByScrewdriver(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+ mCuttingMode = !mCuttingMode;
+ String aMode = mCuttingMode ? "Cutting" : "Slicing";
+ PlayerUtils.messagePlayer(aPlayer, "Mode: " + aMode);
+ mLastRecipe = null;
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ super.saveNBTData(aNBT);
+ aNBT.setBoolean("mCuttingMode", mCuttingMode);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ if (aNBT.hasKey("mCuttingMode")) {
+ mCuttingMode = aNBT.getBoolean("mCuttingMode");
+ } else {
+ mCuttingMode = true;
+ }
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialDehydrator.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialDehydrator.java
new file mode 100644
index 0000000000..9122090f89
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialDehydrator.java
@@ -0,0 +1,250 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+import static gregtech.api.util.GT_StructureUtility.ofCoil;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import javax.annotation.Nonnull;
+
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.HeatingCoilLevel;
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_OverclockCalculator;
+import gregtech.api.util.GT_Recipe;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.minecraft.PlayerUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_IndustrialDehydrator
+ extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialDehydrator> implements ISurvivalConstructable {
+
+ private static int CASING_TEXTURE_ID;
+ private static String mCasingName = "Vacuum Casing";
+ private HeatingCoilLevel mHeatingCapacity;
+ private boolean mDehydratorMode = false;
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialDehydrator> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_IndustrialDehydrator(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ CASING_TEXTURE_ID = TAE.getIndexFromPage(3, 10);
+ }
+
+ public GregtechMetaTileEntity_IndustrialDehydrator(String aName) {
+ super(aName);
+ CASING_TEXTURE_ID = TAE.getIndexFromPage(3, 10);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IndustrialDehydrator(mName);
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Factory Grade Vacuum Furnace")
+ .addInfo("Can toggle the operation temperature with a Screwdriver")
+ .addInfo("All Dehydrator recipes are Low Temp recipes")
+ .addInfo("Speed: +120% | EU Usage: 50% | Parallel: 4")
+ .addInfo("Each 900K over the min. Heat Capacity grants 5% speedup (multiplicatively)")
+ .addInfo("Each 1800K over the min. Heat Capacity allows for one upgraded overclock")
+ .addInfo("Upgraded overclocks reduce recipe time to 25% and increase EU/t to 400%")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 5, 3, true)
+ .addController("Bottom Center")
+ .addCasingInfoMin(mCasingName, 5, false)
+ .addInputBus("Any Casing", 1)
+ .addOutputBus("Any Casing", 1)
+ .addInputHatch("Any Casing", 1)
+ .addOutputHatch("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialDehydrator> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialDehydrator>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC" }, { "HHH", "H-H", "HHH" }, { "HHH", "H-H", "HHH" },
+ { "HHH", "H-H", "HHH" }, { "C~C", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialDehydrator.class)
+ .atLeast(InputBus, OutputBus, Maintenance, Energy, Muffler, InputHatch, OutputHatch)
+ .casingIndex(CASING_TEXTURE_ID)
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings4Misc, 10))))
+ .addElement(
+ 'H',
+ ofCoil(
+ GregtechMetaTileEntity_IndustrialDehydrator::setCoilLevel,
+ GregtechMetaTileEntity_IndustrialDehydrator::getCoilLevel))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 4, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 4, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ setCoilLevel(HeatingCoilLevel.None);
+ return checkPiece(mName, 1, 4, 0) && mCasing >= 5 && getCoilLevel() != HeatingCoilLevel.None && checkHatch();
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return CASING_TEXTURE_ID;
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return mDehydratorMode ? GTPPRecipeMaps.chemicalDehydratorNonCellRecipes : GTPPRecipeMaps.vacuumFurnaceRecipes;
+ }
+
+ @Nonnull
+ @Override
+ public Collection<RecipeMap<?>> getAvailableRecipeMaps() {
+ return Arrays.asList(GTPPRecipeMaps.chemicalDehydratorNonCellRecipes, GTPPRecipeMaps.vacuumFurnaceRecipes);
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialDehydrator;
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Vacuum Furnace / Dehydrator";
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 4;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic() {
+
+ @NotNull
+ @Override
+ protected CheckRecipeResult validateRecipe(@NotNull GT_Recipe recipe) {
+ return recipe.mSpecialValue <= getCoilLevel().getHeat() ? CheckRecipeResultRegistry.SUCCESSFUL
+ : CheckRecipeResultRegistry.insufficientHeat(recipe.mSpecialValue);
+ }
+
+ @NotNull
+ @Override
+ protected GT_OverclockCalculator createOverclockCalculator(@NotNull GT_Recipe recipe) {
+ return super.createOverclockCalculator(recipe).setHeatOC(true)
+ .setHeatDiscount(true)
+ .setRecipeHeat(recipe.mSpecialValue)
+ .setMachineHeat((int) getCoilLevel().getHeat());
+ }
+ }.setSpeedBonus(1F / 2.2F)
+ .setEuModifier(0.5F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ public void onModeChangeByScrewdriver(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+ mDehydratorMode = !mDehydratorMode;
+ String aMode = mDehydratorMode ? "Dehydrator" : "Vacuum Furnace";
+ PlayerUtils.messagePlayer(aPlayer, "Mode: " + aMode);
+ mLastRecipe = null;
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ super.saveNBTData(aNBT);
+ aNBT.setBoolean("mDehydratorMode", mDehydratorMode);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ mDehydratorMode = aNBT.getBoolean("mDehydratorMode");
+ }
+
+ public HeatingCoilLevel getCoilLevel() {
+ return mHeatingCapacity;
+ }
+
+ public void setCoilLevel(HeatingCoilLevel aCoilLevel) {
+ mHeatingCapacity = aCoilLevel;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialElectrolyzer.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialElectrolyzer.java
new file mode 100644
index 0000000000..f12007b952
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialElectrolyzer.java
@@ -0,0 +1,169 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import net.minecraft.item.ItemStack;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_IndustrialElectrolyzer extends
+ GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialElectrolyzer> implements ISurvivalConstructable {
+
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialElectrolyzer> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_IndustrialElectrolyzer(final int aID, final String aName,
+ final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_IndustrialElectrolyzer(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IndustrialElectrolyzer(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Electrolyzer";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Industrial Electrolyzer")
+ .addInfo("180% faster than using single block machines of the same voltage")
+ .addInfo("Only uses 90% of the EU/t normally required")
+ .addInfo("Processes two items per voltage tier")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 3, 3, true)
+ .addController("Front Center")
+ .addCasingInfoMin("Electrolyzer Casings", 6, false)
+ .addInputBus("Any Casing", 1)
+ .addOutputBus("Any Casing", 1)
+ .addInputHatch("Any Casing", 1)
+ .addOutputHatch("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialElectrolyzer> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialElectrolyzer>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC" }, { "C~C", "C-C", "CCC" }, { "CCC", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialElectrolyzer.class)
+ .atLeast(InputBus, OutputBus, Maintenance, Energy, Muffler, InputHatch, OutputHatch)
+ .casingIndex(TAE.GTPP_INDEX(5))
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasingsMisc, 5))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 1, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ return checkPiece(mName, 1, 1, 0) && mCasing >= 6 && checkHatch();
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return TAE.GTPP_INDEX(5);
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return GTPPRecipeMaps.electrolyzerNonCellRecipes;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic().setSpeedBonus(1F / 2.8F)
+ .setEuModifier(0.9F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialElectrolyzer;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 2 * GT_Utility.getTier(this.getMaxInputVoltage());
+ }
+
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialExtruder.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialExtruder.java
new file mode 100644
index 0000000000..ea61048f33
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialExtruder.java
@@ -0,0 +1,194 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import net.minecraft.block.Block;
+import net.minecraft.item.ItemStack;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.SoundResource;
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_IndustrialExtruder
+ extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialExtruder> implements ISurvivalConstructable {
+
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialExtruder> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_IndustrialExtruder(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_IndustrialExtruder(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IndustrialExtruder(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Extruder";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Material Extruder")
+ .addInfo("250% faster than using single block machines of the same voltage")
+ .addInfo("Processes four items per voltage tier")
+ .addInfo("Extrusion Shape for recipe goes in the Input Bus")
+ .addInfo("Each Input Bus can have a different shape!")
+ .addInfo("You can use several input buses per multiblock")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 3, 5, true)
+ .addController("Front Center")
+ .addCasingInfoMin("Inconel Reinforced Casings", 14, false)
+ .addInputBus("Any Casing", 1)
+ .addOutputBus("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialExtruder> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialExtruder>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC", "CCC", "CCC" }, { "C~C", "C-C", "C-C", "C-C", "CCC" },
+ { "CCC", "CCC", "CCC", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialExtruder.class)
+ .atLeast(InputBus, OutputBus, Maintenance, Energy, Muffler)
+ .casingIndex(getCasingTextureIndex())
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(getCasingBlock(), getCasingMeta()))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 1, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ return checkPiece(mName, 1, 1, 0) && mCasing >= 14 && checkHatch();
+ }
+
+ @Override
+ protected SoundResource getProcessStartSound() {
+ return SoundResource.IC2_MACHINES_COMPRESSOR_OP;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return TAE.GTPP_INDEX(33);
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return RecipeMaps.extruderRecipes;
+ }
+
+ @Override
+ public int getRecipeCatalystPriority() {
+ return -1;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic().setSpeedBonus(1F / 3.5F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return (4 * GT_Utility.getTier(this.getMaxInputVoltage()));
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialExtruder;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ public Block getCasingBlock() {
+ return ModBlocks.blockCasings3Misc;
+ }
+
+ public byte getCasingMeta() {
+ return 1;
+ }
+
+ public byte getCasingTextureIndex() {
+ return (byte) TAE.GTPP_INDEX(33);
+ }
+
+ @Override
+ public boolean isInputSeparationEnabled() {
+ return true;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialFluidHeater.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialFluidHeater.java
new file mode 100644
index 0000000000..a34532ee83
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialFluidHeater.java
@@ -0,0 +1,204 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import net.minecraft.block.Block;
+import net.minecraft.item.ItemStack;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_IndustrialFluidHeater extends
+ GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialFluidHeater> implements ISurvivalConstructable {
+
+ private int mCasing1;
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialFluidHeater> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_IndustrialFluidHeater(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_IndustrialFluidHeater(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IndustrialFluidHeater(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Fluid Heater";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Industrial Fluid Heater")
+ .addInfo("120% faster than using single block machines of the same voltage")
+ .addInfo("Only uses 90% of the EU/t normally required")
+ .addInfo("Processes eight items per voltage tier")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(5, 6, 5, true)
+ .addController("Front Center")
+ .addCasingInfoMin("Top/Bottom layer: Multi-use Casings", 34, false)
+ .addCasingInfoMin("Middle layers: Thermal Containment Casing", 47, false)
+ .addInputBus("Bottom Layer (optional)", 1)
+ .addInputHatch("Bottom Layer", 1)
+ .addOutputBus("Top Layer (optional)", 1)
+ .addOutputHatch("Top Layer", 1)
+ .addEnergyHatch("Any Multi-use Casing", 1)
+ .addMaintenanceHatch("Any Multi-use Casing", 1)
+ .addMufflerHatch("Any Multi-use Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialFluidHeater> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialFluidHeater>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { " TTT ", "TTTTT", "TTTTT", "TTTTT", " TTT " },
+ { " XXX ", "X---X", "X---X", "X---X", " XXX " },
+ { " XXX ", "X---X", "X---X", "X---X", " XXX " },
+ { " XXX ", "X---X", "X---X", "X---X", " XXX " },
+ { " X~X ", "X---X", "X---X", "X---X", " XXX " },
+ { " BBB ", "BBBBB", "BBBBB", "BBBBB", " BBB " }, }))
+ .addElement(
+ 'B',
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialFluidHeater.class)
+ .atLeast(InputBus, InputHatch, Maintenance, Energy, Muffler)
+ .casingIndex(getCasingTextureIndex())
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing1, ofBlock(getCasingBlock2(), getCasingMeta2()))))
+ .addElement('X', ofBlock(getCasingBlock1(), getCasingMeta1()))
+ .addElement(
+ 'T',
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialFluidHeater.class)
+ .atLeast(OutputBus, OutputHatch, Maintenance, Energy, Muffler)
+ .casingIndex(getCasingTextureIndex())
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing1, ofBlock(getCasingBlock2(), getCasingMeta2()))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 2, 4, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 2, 4, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing1 = 0;
+ boolean didBuild = checkPiece(mName, 2, 4, 0);
+ log("Built? " + didBuild + ", " + mCasing1);
+ return didBuild && mCasing1 >= 34 && checkHatch();
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return TAE.getIndexFromPage(0, 1);
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return RecipeMaps.fluidHeaterRecipes;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic().setSpeedBonus(1F / 2.2F)
+ .setEuModifier(0.9F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return (8 * GT_Utility.getTier(this.getMaxInputVoltage()));
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialThermalCentrifuge;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ public Block getCasingBlock1() {
+ return ModBlocks.blockCasings2Misc;
+ }
+
+ public byte getCasingMeta1() {
+ return 11;
+ }
+
+ public Block getCasingBlock2() {
+ return ModBlocks.blockCasings3Misc;
+ }
+
+ public byte getCasingMeta2() {
+ return 2;
+ }
+
+ public byte getCasingTextureIndex() {
+ return (byte) TAE.getIndexFromPage(2, 2);
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialForgeHammer.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialForgeHammer.java
new file mode 100644
index 0000000000..8e2f040d75
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialForgeHammer.java
@@ -0,0 +1,244 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlocksTiered;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.enums.Mods.EnderIO;
+import static gregtech.api.enums.Mods.Railcraft;
+import static gregtech.api.enums.Mods.ThaumicBases;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import net.minecraft.block.Block;
+import net.minecraft.init.Blocks;
+import net.minecraft.item.ItemStack;
+
+import org.apache.commons.lang3.tuple.Pair;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.ITierConverter;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import cpw.mods.fml.common.registry.GameRegistry;
+import gregtech.api.enums.SoundResource;
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+@SuppressWarnings("SpellCheckingInspection")
+public class GregtechMetaTileEntity_IndustrialForgeHammer extends
+ GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialForgeHammer> implements ISurvivalConstructable {
+
+ private int mCasing;
+ private int mAnvilTier = 0;
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialForgeHammer> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_IndustrialForgeHammer(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_IndustrialForgeHammer(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IndustrialForgeHammer(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Forge Hammer";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Industrial Forge Hammer")
+ .addInfo("Speed: +100% | EU Usage: 100% | Parallel: Tier x Anvil Tier x 8")
+ .addInfo("T1 - Vanilla Anvil");
+ if (Railcraft.isModLoaded()) {
+ tt.addInfo("T2 - Steel Anvil");
+ }
+ if (EnderIO.isModLoaded()) {
+ tt.addInfo("T3 - Dark Steel Anvil");
+ }
+ if (ThaumicBases.isModLoaded()) {
+ tt.addInfo("T3 - Thaumium Anvil");
+ tt.addInfo("T4 - Void Metal Anvil");
+ }
+
+ tt.addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 3, 3, true)
+ .addController("Front Center")
+ .addCasingInfoMin("Forge Casing", 6, false)
+ .addInputBus("Any Casing", 1)
+ .addOutputBus("Any Casing", 1)
+ .addInputHatch("Any Casing", 1)
+ .addOutputHatch("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .addOtherStructurePart("Anvil", "In the center of 3x3x3 structure", 2)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialForgeHammer> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ Map<Block, Integer> anvilTiers = new HashMap<>();
+
+ anvilTiers.put(Blocks.anvil, 1);
+
+ if (Railcraft.isModLoaded()) {
+ anvilTiers.put(GameRegistry.findBlock(Railcraft.ID, "anvil"), 2);
+ }
+
+ if (EnderIO.isModLoaded()) {
+ anvilTiers.put(GameRegistry.findBlock(EnderIO.ID, "blockDarkSteelAnvil"), 3);
+ }
+
+ if (ThaumicBases.isModLoaded()) {
+ anvilTiers.put(GameRegistry.findBlock(ThaumicBases.ID, "thaumicAnvil"), 3);
+ anvilTiers.put(GameRegistry.findBlock(ThaumicBases.ID, "voidAnvil"), 4);
+ }
+
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialForgeHammer>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC" }, { "C~C", "CAC", "CCC" }, { "CCC", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialForgeHammer.class)
+ .atLeast(InputBus, OutputBus, Maintenance, Energy, Muffler, InputHatch, OutputHatch)
+ .casingIndex(TAE.getIndexFromPage(1, 11))
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings5Misc, 6))))
+ .addElement(
+ 'A',
+ ofBlocksTiered(
+ anvilTierConverter(anvilTiers),
+ getAllAnvilTiers(anvilTiers),
+ 0,
+ GregtechMetaTileEntity_IndustrialForgeHammer::setAnvilTier,
+ GregtechMetaTileEntity_IndustrialForgeHammer::getAnvilTier))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ private static List<Pair<Block, Integer>> getAllAnvilTiers(Map<Block, Integer> anvilTiers) {
+ return anvilTiers.entrySet()
+ .stream()
+ .map(e -> Pair.of(e.getKey(), e.getValue()))
+ .collect(Collectors.toList());
+ }
+
+ private static ITierConverter<Integer> anvilTierConverter(Map<Block, Integer> anvilTiers) {
+ return (block, meta) -> block == null ? 0 : anvilTiers.getOrDefault(block, 0);
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 1, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ return checkPiece(mName, 1, 1, 0) && mCasing >= 6 && checkHatch();
+ }
+
+ @Override
+ protected SoundResource getProcessStartSound() {
+ return SoundResource.RANDOM_ANVIL_USE;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return TAE.getIndexFromPage(1, 11);
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return RecipeMaps.hammerRecipes;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic().setSpeedBonus(1 / 2F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return (8 * getAnvilTier() * GT_Utility.getTier(this.getMaxInputVoltage()));
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialForgeHammer;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ private void setAnvilTier(int tier) {
+ mAnvilTier = tier;
+ }
+
+ private int getAnvilTier() {
+ return mAnvilTier;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialMacerator.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialMacerator.java
new file mode 100644
index 0000000000..5591b9fbe8
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialMacerator.java
@@ -0,0 +1,458 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import java.util.List;
+import java.util.Random;
+
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.StatCollector;
+import net.minecraft.world.World;
+import net.minecraftforge.common.util.Constants.NBT;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.GregTech_API;
+import gregtech.api.enums.SoundResource;
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.minecraft.ItemUtils;
+import gtPlusPlus.xmod.gregtech.api.enums.GregtechItemList;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+import mcp.mobius.waila.api.IWailaConfigHandler;
+import mcp.mobius.waila.api.IWailaDataAccessor;
+
+public class GregtechMetaTileEntity_IndustrialMacerator
+ extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialMacerator> implements ISurvivalConstructable {
+
+ private int controllerTier = 1;
+ private int mCasing;
+ private int mPerLayer;
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialMacerator> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_IndustrialMacerator(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_IndustrialMacerator(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IndustrialMacerator(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Macerator/Pulverizer";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller block for the Industrial Maceration Stack")
+ .addInfo("60% faster than using single block machines of the same voltage")
+ .addInfo("Maximum of n*tier parallels, LV = Tier 1, MV = Tier 2, etc.")
+ .addInfo("n=2 initially. n=8 after inserting Maceration Upgrade Chip.")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 6, 3, true)
+ .addController("Bottom center")
+ .addCasingInfoMin("Maceration Stack Casings (After upgrade)", 26, false)
+ .addCasingInfoMin("Stable Titanium Casings (Before upgrade)", 26, false)
+ .addInputBus("Bottom casing", 1)
+ .addEnergyHatch("Any casing", 1)
+ .addMaintenanceHatch("Any casing", 1)
+ .addOutputBus("One per layer except bottom layer", 2)
+ .addMufflerHatch("Any casing except bottom layer", 2)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialMacerator> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialMacerator>builder()
+ .addShape(mName + "top1", transpose(new String[][] { { "ccc", "ccc", "ccc" }, }))
+ .addShape(mName + "mid1", transpose(new String[][] { { "ccc", "c-c", "ccc" }, }))
+ .addShape(mName + "bottom1", transpose(new String[][] { { "b~b", "bbb", "bbb" }, }))
+ .addShape(mName + "top2", transpose(new String[][] { { "CCC", "CCC", "CCC" }, }))
+ .addShape(mName + "mid2", transpose(new String[][] { { "CCC", "C-C", "CCC" }, }))
+ .addShape(mName + "bottom2", transpose(new String[][] { { "B~B", "BBB", "BBB" }, }))
+ .addElement(
+ 'C',
+ ofChain(
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialMacerator.class).anyOf(OutputBus)
+ .shouldReject(t -> t.mPerLayer + 1 == t.mOutputBusses.size())
+ .disallowOnly(ForgeDirection.UP, ForgeDirection.DOWN)
+ .casingIndex(TAE.GTPP_INDEX(7))
+ .dot(2)
+ .build(),
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialMacerator.class)
+ .atLeast(Energy, Maintenance, Muffler)
+ .disallowOnly(ForgeDirection.UP, ForgeDirection.DOWN)
+ .casingIndex(TAE.GTPP_INDEX(7))
+ .dot(2)
+ .build(),
+ onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasingsMisc, 7))))
+ .addElement(
+ 'B',
+ ofChain(
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialMacerator.class)
+ .atLeast(Energy, Maintenance, InputBus)
+ .disallowOnly(ForgeDirection.UP)
+ .casingIndex(TAE.GTPP_INDEX(7))
+ .dot(2)
+ .build(),
+ onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasingsMisc, 7))))
+ .addElement(
+ 'c',
+ ofChain(
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialMacerator.class).anyOf(OutputBus)
+ .shouldReject(t -> t.mPerLayer + 1 == t.mOutputBusses.size())
+ .disallowOnly(ForgeDirection.UP, ForgeDirection.DOWN)
+ .casingIndex(GT_Utility.getCasingTextureIndex(GregTech_API.sBlockCasings4, 2))
+ .dot(2)
+ .build(),
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialMacerator.class)
+ .atLeast(Energy, Maintenance, Muffler)
+ .disallowOnly(ForgeDirection.UP, ForgeDirection.DOWN)
+ .casingIndex(GT_Utility.getCasingTextureIndex(GregTech_API.sBlockCasings4, 2))
+ .dot(2)
+ .build(),
+ onElementPass(x -> ++x.mCasing, ofBlock(GregTech_API.sBlockCasings4, 2))))
+ .addElement(
+ 'b',
+ ofChain(
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialMacerator.class)
+ .atLeast(Energy, Maintenance, InputBus)
+ .disallowOnly(ForgeDirection.UP)
+ .casingIndex(GT_Utility.getCasingTextureIndex(GregTech_API.sBlockCasings4, 2))
+ .dot(2)
+ .build(),
+ onElementPass(x -> ++x.mCasing, ofBlock(GregTech_API.sBlockCasings4, 2))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName + "bottom" + controllerTier, stackSize, hintsOnly, 1, 0, 0);
+ buildPiece(mName + "mid" + controllerTier, stackSize, hintsOnly, 1, 1, 0);
+ buildPiece(mName + "mid" + controllerTier, stackSize, hintsOnly, 1, 2, 0);
+ buildPiece(mName + "mid" + controllerTier, stackSize, hintsOnly, 1, 3, 0);
+ buildPiece(mName + "mid" + controllerTier, stackSize, hintsOnly, 1, 4, 0);
+ buildPiece(mName + "top" + controllerTier, stackSize, hintsOnly, 1, 5, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ int built;
+ built = survivialBuildPiece(
+ mName + "bottom" + controllerTier,
+ stackSize,
+ 1,
+ 0,
+ 0,
+ elementBudget,
+ env,
+ false,
+ true);
+ mPerLayer = 0;
+ if (built >= 0) return built;
+ built = survivialBuildPiece(
+ mName + "mid" + controllerTier,
+ stackSize,
+ 1,
+ 1,
+ 0,
+ elementBudget,
+ env,
+ false,
+ true);
+ mPerLayer = 1;
+ if (built >= 0) return built;
+ built = survivialBuildPiece(
+ mName + "mid" + controllerTier,
+ stackSize,
+ 1,
+ 2,
+ 0,
+ elementBudget,
+ env,
+ false,
+ true);
+ if (built >= 0) return built;
+ mPerLayer = 2;
+ built = survivialBuildPiece(
+ mName + "mid" + controllerTier,
+ stackSize,
+ 1,
+ 3,
+ 0,
+ elementBudget,
+ env,
+ false,
+ true);
+ if (built >= 0) return built;
+ mPerLayer = 3;
+ built = survivialBuildPiece(
+ mName + "mid" + controllerTier,
+ stackSize,
+ 1,
+ 4,
+ 0,
+ elementBudget,
+ env,
+ false,
+ true);
+ if (built >= 0) return built;
+ mPerLayer = 4;
+ return survivialBuildPiece(mName + "top" + controllerTier, stackSize, 1, 5, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ mPerLayer = 0;
+ if (checkPiece(mName + "bottom" + controllerTier, 1, 0, 0)) {
+ while (mPerLayer < 4) {
+ if (!checkPiece(mName + "mid" + controllerTier, 1, mPerLayer + 1, 0)
+ || mPerLayer + 1 != mOutputBusses.size()) return false;
+ mPerLayer++;
+ }
+ return checkPiece(mName + "top" + controllerTier, 1, 5, 0) && mOutputBusses.size() == 5
+ && mCasing >= 26
+ && checkHatch();
+ }
+ return false;
+ }
+
+ @Override
+ protected SoundResource getProcessStartSound() {
+ return SoundResource.IC2_MACHINES_MACERATOR_OP;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_MatterFab_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_MatterFab;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return switch (controllerTier) {
+ case 2 -> TAE.GTPP_INDEX(7);
+ default -> GT_Utility.getCasingTextureIndex(GregTech_API.sBlockCasings4, 2);
+ };
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return RecipeMaps.maceratorRecipes;
+ }
+
+ @Override
+ public int getRecipeCatalystPriority() {
+ return -10;
+ }
+
+ @Override
+ public void onPreTick(final IGregTechTileEntity aBaseMetaTileEntity, final long aTick) {
+ super.onPreTick(aBaseMetaTileEntity, aTick);
+ if ((aBaseMetaTileEntity.isClientSide()) && (aBaseMetaTileEntity.isActive())
+ && (aBaseMetaTileEntity.getFrontFacing() != ForgeDirection.UP)
+ && (aBaseMetaTileEntity.getCoverIDAtSide(ForgeDirection.UP) == 0)
+ && (!aBaseMetaTileEntity.getOpacityAtSide(ForgeDirection.UP))) {
+ final Random tRandom = aBaseMetaTileEntity.getWorld().rand;
+ aBaseMetaTileEntity.getWorld()
+ .spawnParticle(
+ "smoke",
+ (aBaseMetaTileEntity.getXCoord() + 0.8F) - (tRandom.nextFloat() * 0.6F),
+ aBaseMetaTileEntity.getYCoord() + 0.3f + (tRandom.nextFloat() * 0.2F),
+ (aBaseMetaTileEntity.getZCoord() + 1.2F) - (tRandom.nextFloat() * 1.6F),
+ 0.0D,
+ 0.0D,
+ 0.0D);
+ }
+ }
+
+ @Override
+ public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {
+ super.onPostTick(aBaseMetaTileEntity, aTick);
+ if (aBaseMetaTileEntity.isServerSide() && aTick % 20 == 0 && controllerTier == 1) {
+ ItemStack aGuiStack = this.getControllerSlot();
+ if (GregtechItemList.Maceration_Upgrade_Chip.isStackEqual(aGuiStack, false, true)) {
+ controllerTier = 2;
+ mInventory[1] = ItemUtils.depleteStack(aGuiStack);
+ markDirty();
+ // schedule a structure check
+ mUpdated = true;
+ }
+ }
+ }
+
+ @Override
+ public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer, ForgeDirection side,
+ float aX, float aY, float aZ) {
+ if (controllerTier == 1 && !aPlayer.isSneaking()) {
+ ItemStack heldItem = aPlayer.getHeldItem();
+ if (GregtechItemList.Maceration_Upgrade_Chip.isStackEqual(heldItem, false, true)) {
+ controllerTier = 2;
+ aPlayer.setCurrentItemOrArmor(0, ItemUtils.depleteStack(heldItem));
+ if (getBaseMetaTileEntity().isServerSide()) {
+ markDirty();
+ aPlayer.inventory.markDirty();
+ // schedule a structure check
+ mUpdated = true;
+ }
+ return true;
+ }
+ }
+ return super.onRightclick(aBaseMetaTileEntity, aPlayer, side, aX, aY, aZ);
+ }
+
+ @Override
+ public void onValueUpdate(byte aValue) {
+ controllerTier = aValue;
+ }
+
+ @Override
+ public byte getUpdateData() {
+ return (byte) controllerTier;
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ super.saveNBTData(aNBT);
+ aNBT.setByte("mTier", (byte) controllerTier);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ if (!aNBT.hasKey("mTier", NBT.TAG_BYTE))
+ // we assume old macerators are all T2 variants, as they were made before price reduction and shouldn't need
+ // to worry about upgrading
+ controllerTier = 2;
+ else controllerTier = aNBT.getByte("mTier");
+ }
+
+ @Override
+ public void initDefaultModes(NBTTagCompound aNBT) {
+ super.initDefaultModes(aNBT);
+ if (aNBT == null || !aNBT.hasKey("mTier")) {
+ controllerTier = 1;
+ } else {
+ controllerTier = aNBT.getByte("mTier");
+ }
+ }
+
+ @Override
+ public void setItemNBT(NBTTagCompound aNBT) {
+ super.setItemNBT(aNBT);
+ aNBT.setByte("mTier", (byte) controllerTier);
+ }
+
+ @Override
+ public void addAdditionalTooltipInformation(ItemStack stack, List<String> tooltip) {
+ super.addAdditionalTooltipInformation(stack, tooltip);
+ NBTTagCompound aNBT = stack.getTagCompound();
+ int tier;
+ if (aNBT == null || !aNBT.hasKey("mTier")) {
+ tier = 1;
+ } else {
+ tier = aNBT.getInteger("mTier");
+ }
+ tooltip.add(StatCollector.translateToLocalFormatted("tooltip.large_macerator.tier", tier));
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic().setSpeedBonus(1F / 1.6F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ final long tVoltage = getMaxInputVoltage();
+ final byte tTier = (byte) Math.max(1, GT_Utility.getTier(tVoltage));
+ return Math.max(1, (controllerTier == 1 ? 2 : 8) * tTier);
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialMacerator;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public boolean isOverclockerUpgradable() {
+ return true;
+ }
+
+ @Override
+ public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y,
+ int z) {
+ super.getWailaNBTData(player, tile, tag, world, x, y, z);
+ tag.setInteger("tier", controllerTier);
+ }
+
+ @Override
+ public void getWailaBody(ItemStack itemStack, List<String> currentTip, IWailaDataAccessor accessor,
+ IWailaConfigHandler config) {
+ super.getWailaBody(itemStack, currentTip, accessor, config);
+ final NBTTagCompound tag = accessor.getNBTData();
+ if (tag.hasKey("tier")) {
+ currentTip.add(
+ "Tier: " + EnumChatFormatting.YELLOW
+ + GT_Utility.formatNumbers(tag.getInteger("tier"))
+ + EnumChatFormatting.RESET);
+ }
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialMixer.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialMixer.java
new file mode 100644
index 0000000000..3f4c4ccfa4
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialMixer.java
@@ -0,0 +1,213 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.StatCollector;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.GregTech_API;
+import gregtech.api.enums.SoundResource;
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_IndustrialMixer
+ extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialMixer> implements ISurvivalConstructable {
+
+ public static int CASING_TEXTURE_ID;
+ public static String mCasingName = "Multi-Use Casing";
+ public static String mCasingName2 = "Titanium Turbine Casing";
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialMixer> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_IndustrialMixer(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ CASING_TEXTURE_ID = TAE.getIndexFromPage(2, 2);
+ inputSeparation = true;
+ }
+
+ public GregtechMetaTileEntity_IndustrialMixer(final String aName) {
+ super(aName);
+ CASING_TEXTURE_ID = TAE.getIndexFromPage(2, 2);
+ inputSeparation = true;
+ }
+
+ @Override
+ public void loadNBTData(final NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ if (!aNBT.hasKey(INPUT_SEPARATION_NBT_KEY)) {
+ if (aNBT.hasKey("isBussesSeparate")) {
+ inputSeparation = aNBT.getBoolean("isBussesSeparate");
+ }
+ // Fallback for existing mixers
+ else {
+ inputSeparation = true;
+ }
+ }
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IndustrialMixer(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Mixer";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Industrial Mixer")
+ .addInfo("250% faster than using single block machines of the same voltage")
+ .addInfo("Processes eight recipes per voltage tier")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 4, 3, false)
+ .addController("Second Layer Center")
+ .addCasingInfoMin(mCasingName, 6, false)
+ .addCasingInfoMin(mCasingName2, 2, false)
+ .addInputBus("Any Casing", 1)
+ .addOutputBus("Any Casing", 1)
+ .addInputHatch("Any Casing", 1)
+ .addOutputHatch("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialMixer> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialMixer>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC" }, { "CCC", "CMC", "CCC" }, { "C~C", "CMC", "CCC" },
+ { "CCC", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialMixer.class)
+ .atLeast(InputBus, OutputBus, Maintenance, Energy, Muffler, InputHatch, OutputHatch)
+ .casingIndex(CASING_TEXTURE_ID)
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings3Misc, 2))))
+ .addElement('M', ofBlock(GregTech_API.sBlockCasings4, 11))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 2, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 2, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ return checkPiece(mName, 1, 2, 0) && mCasing >= 6 && checkHatch();
+ }
+
+ @Override
+ protected SoundResource getProcessStartSound() {
+ return SoundResource.IC2_MACHINES_COMPRESSOR_OP;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return CASING_TEXTURE_ID;
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return GTPPRecipeMaps.mixerNonCellRecipes;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic().setSpeedBonus(1F / 3.5F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return (8 * GT_Utility.getTier(this.getMaxInputVoltage()));
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialMixer;
+ }
+
+ @Override
+ public void onModeChangeByScrewdriver(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+ inputSeparation = !inputSeparation;
+ GT_Utility.sendChatToPlayer(
+ aPlayer,
+ StatCollector.translateToLocal("GT5U.machines.separatebus") + " " + inputSeparation);
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public boolean supportsInputSeparation() {
+ return true;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialMolecularTransformer.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialMolecularTransformer.java
new file mode 100644
index 0000000000..02b0bcf978
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialMolecularTransformer.java
@@ -0,0 +1,241 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import net.minecraft.block.Block;
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits;
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.GregTech_API;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_IndustrialMolecularTransformer
+ extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialMolecularTransformer>
+ implements ISurvivalConstructable {
+
+ private static final int CASING_TEXTURE_ID = 48;
+ private int mCasing = 0;
+
+ public GregtechMetaTileEntity_IndustrialMolecularTransformer(final int aID, final String aName,
+ final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_IndustrialMolecularTransformer(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IndustrialMolecularTransformer(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Molecular Transformer";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Changes the structure of items to produce new ones")
+ .addInfo("Maximum 1x of each bus/hatch.")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(7, 7, 7, false)
+ .addController("Top Center")
+ .addCasingInfoMin("Robust Tungstensteel Machine Casing", 40, false)
+ .addCasingInfoMin("Tungstensteel Coils", 16, false)
+ .addCasingInfoMin("Molecular Containment Casing", 52, false)
+ .addCasingInfoMin("High Voltage Current Capacitor", 32, false)
+ .addCasingInfoMin("Particle Containment Casing", 4, false)
+ .addCasingInfoMin("Resonance Chamber I", 5, false)
+ .addCasingInfoMin("Modulator I", 4, false)
+ .addInputBus("Any Robust Tungstensteel Machine Casing", 1)
+ .addOutputBus("Any Robust Tungstensteel Machine Casing", 1)
+ .addEnergyHatch("Any Robust Tungstensteel Machine Casing", 1)
+ .addMaintenanceHatch("Any Robust Tungstensteel Machine Casing", 1)
+ .addMufflerHatch("Any Robust Tungstensteel Machine Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ private static final String STRUCTURE_PIECE_MAIN = "main";
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialMolecularTransformer> STRUCTURE_DEFINITION = null;
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialMolecularTransformer> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialMolecularTransformer>builder()
+ .addShape(
+ STRUCTURE_PIECE_MAIN,
+ (new String[][] { { " ", " ", " xxx ", " x~x ", " xxx ", " ", " " },
+ { " ", " xxx ", " xyyyx ", " xyzyx ", " xyyyx ", " xxx ", " " },
+ { " ", " xxx ", " xyyyx ", " xyzyx ", " xyyyx ", " xxx ", " " },
+ { " ", " xxx ", " xyyyx ", " xyzyx ", " xyyyx ", " xxx ", " " },
+ { " t ", " ttxtt ", " tyyyt ", "txyzyxt", " tyyyt ", " ttxtt ", " t " },
+ { " c ", " ccecc ", " cxfxc ", "cefefec", " cxfxc ", " ccecc ", " c " },
+ { " h ", " hhhhh ", " hhhhh ", "hhhhhhh", " hhhhh ", " hhhhh ", " h " }, }))
+ .addElement('x', ofBlock(getCasingBlock(), getCasingMeta()))
+ .addElement('y', ofBlock(getCasingBlock(), getCasingMeta2()))
+ .addElement('z', ofBlock(getCasingBlock(), getCasingMeta3()))
+ .addElement('e', ofBlock(getCasingBlock2(), 0))
+ .addElement('f', ofBlock(getCasingBlock2(), 4))
+ .addElement('c', ofBlock(getCoilBlock(), 3))
+ .addElement('t', ofBlock(getCasingBlock3(), getTungstenCasingMeta()))
+ .addElement(
+ 'h',
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialMolecularTransformer.class)
+ .atLeast(InputBus, OutputBus, Maintenance, Energy, Muffler)
+ .casingIndex(getCasingTextureIndex())
+ .dot(1)
+ .buildAndChain(
+ onElementPass(x -> ++x.mCasing, ofBlock(getCasingBlock3(), getTungstenCasingMeta()))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(STRUCTURE_PIECE_MAIN, stackSize, hintsOnly, 3, 3, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(STRUCTURE_PIECE_MAIN, stackSize, 3, 3, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ boolean aDidBuild = checkPiece(STRUCTURE_PIECE_MAIN, 3, 3, 0);
+ if (this.mInputBusses.size() != 1 || this.mOutputBusses.size() != 1 || this.mEnergyHatches.size() != 1) {
+ return false;
+ }
+ // there are 16 slot that only allow casing, so we subtract this from the grand total required
+ return aDidBuild && mCasing >= 40 - 16 && checkHatch();
+ }
+
+ protected static int getCasingTextureIndex() {
+ return CASING_TEXTURE_ID;
+ }
+
+ protected static Block getCasingBlock() {
+ return ModBlocks.blockSpecialMultiCasings;
+ }
+
+ protected static Block getCasingBlock2() {
+ return ModBlocks.blockSpecialMultiCasings2;
+ }
+
+ protected static Block getCasingBlock3() {
+ return GregTech_API.sBlockCasings4;
+ }
+
+ protected static Block getCoilBlock() {
+ return GregTech_API.sBlockCasings5;
+ }
+
+ protected static int getCasingMeta() {
+ return 11;
+ }
+
+ protected static int getCasingMeta2() {
+ return 12;
+ }
+
+ protected static int getCasingMeta3() {
+ return 13;
+ }
+
+ protected static int getTungstenCasingMeta() {
+ return 0;
+ }
+
+ @Override
+ protected IAlignmentLimits getInitialAlignmentLimits() {
+ return (d, r, f) -> d == ForgeDirection.UP;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return 44;
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return GTPPRecipeMaps.molecularTransformerRecipes;
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(final ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic();
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 1;
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiMolecularTransformer;
+ }
+
+ @Override
+ public int getDamageToComponent(final ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialMultiMachine.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialMultiMachine.java
new file mode 100644
index 0000000000..52c7736ae3
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialMultiMachine.java
@@ -0,0 +1,514 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+import static gregtech.api.util.GT_Utility.filterValidMTEs;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Stream;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.StatCollector;
+import net.minecraft.world.World;
+import net.minecraftforge.common.util.ForgeDirection;
+import net.minecraftforge.fluids.FluidStack;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_InputBus;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_MultiInput;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.util.GT_LanguageManager;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.GT_Utility;
+import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_CraftingInput_ME;
+import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_Input_ME;
+import gregtech.common.tileentities.machines.IDualInputHatch;
+import gregtech.common.tileentities.machines.IDualInputInventory;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.recipe.common.CI;
+import gtPlusPlus.core.util.minecraft.ItemUtils;
+import gtPlusPlus.core.util.minecraft.PlayerUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Solidifier;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+import mcp.mobius.waila.api.IWailaConfigHandler;
+import mcp.mobius.waila.api.IWailaDataAccessor;
+
+public class GregtechMetaTileEntity_IndustrialMultiMachine extends
+ GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialMultiMachine> implements ISurvivalConstructable {
+
+ protected int mInternalMode = 0;
+ private static final int MODE_COMPRESSOR = 0;
+ private static final int MODE_LATHE = 1;
+ private static final int MODE_MAGNETIC = 2;
+ private static final int MODE_FERMENTER = 3;
+ private static final int MODE_FLUIDEXTRACT = 4;
+ private static final int MODE_EXTRACTOR = 5;
+ private static final int MODE_LASER = 6;
+ private static final int MODE_AUTOCLAVE = 7;
+ private static final int MODE_FLUIDSOLIDIFY = 8;
+ private static final int[][] MODE_MAP = new int[][] { { 0, 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 } };
+ public static final String[] aToolTipNames = new String[9];
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialMultiMachine> STRUCTURE_DEFINITION = null;
+
+ static {
+ for (int id = 0; id < 9; id++) {
+ RecipeMap<?> recipeMap = getRecipeMap(id);
+ if (recipeMap != null) {
+ String aNEI = GT_LanguageManager.getTranslation(getRecipeMap(id).unlocalizedName);
+ aToolTipNames[id] = aNEI != null ? aNEI : "BAD NEI NAME (Report to Github)";
+ }
+ }
+ }
+
+ public GregtechMetaTileEntity_IndustrialMultiMachine(final int aID, final String aName,
+ final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_IndustrialMultiMachine(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IndustrialMultiMachine(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Nine in One";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ String[] aBuiltStrings = new String[3];
+ aBuiltStrings[0] = aToolTipNames[0] + ", " + aToolTipNames[1] + ", " + aToolTipNames[2];
+ aBuiltStrings[1] = aToolTipNames[3] + ", " + aToolTipNames[4] + ", " + aToolTipNames[5];
+ aBuiltStrings[2] = aToolTipNames[6] + ", " + aToolTipNames[7] + ", " + aToolTipNames[8];
+
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Industrial Multi-Machine")
+ .addInfo("250% faster than using single block machines of the same voltage")
+ .addInfo("Only uses 80% of the EU/t normally required")
+ .addInfo("Processes two items per voltage tier")
+ .addInfo("Machine Type: Metal - " + EnumChatFormatting.YELLOW + aBuiltStrings[0] + EnumChatFormatting.RESET)
+ .addInfo("Machine Type: Fluid - " + EnumChatFormatting.YELLOW + aBuiltStrings[1] + EnumChatFormatting.RESET)
+ .addInfo("Machine Type: Misc - " + EnumChatFormatting.YELLOW + aBuiltStrings[2] + EnumChatFormatting.RESET)
+ .addInfo("Read Multi-Machine Manual for extra information")
+ .addInfo(
+ EnumChatFormatting.AQUA + "You can use Solidifier Hatch to solidify multiple liquids."
+ + EnumChatFormatting.RESET)
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 3, 3, true)
+ .addController("Front Center")
+ .addCasingInfoMin("Multi-Use Casings", 6, false)
+ .addInputBus("Any Casing", 1)
+ .addOutputBus("Any Casing", 1)
+ .addInputHatch("Any Casing", 1)
+ .addOutputHatch("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialMultiMachine> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialMultiMachine>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC" }, { "C~C", "C-C", "CCC" }, { "CCC", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialMultiMachine.class)
+ .atLeast(InputBus, OutputBus, Maintenance, Energy, Muffler, InputHatch, OutputHatch)
+ .casingIndex(getTextureIndex())
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings3Misc, 2))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 1, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ return checkPiece(mName, 1, 1, 0) && mCasing >= 6 && checkHatch();
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return getTextureIndex();
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return (2 * GT_Utility.getTier(this.getMaxInputVoltage()));
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ if (mInternalMode == 0) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialMultiMachine_ModeMetal;
+ } else if (mInternalMode == 1) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialMultiMachine_ModeFluid;
+ } else { // config 2
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialMultiMachine_ModeMisc;
+ }
+ }
+
+ public int getTextureIndex() {
+ return TAE.getIndexFromPage(2, 2);
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ private ItemStack getCircuit(ItemStack[] t) {
+ for (ItemStack j : t) {
+ if (j.getItem() == CI.getNumberedCircuit(0)
+ .getItem()) {
+ if (j.getItemDamage() >= 20 && j.getItemDamage() <= 22) {
+ return j;
+ }
+ }
+ }
+ return null;
+ }
+
+ private int getCircuitID(ItemStack circuit) {
+ int H = circuit.getItemDamage();
+ int T = (H == 20 ? 0 : (H == 21 ? 1 : (H == 22 ? 2 : -1)));
+ return MODE_MAP[this.mInternalMode][T];
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return null;
+ }
+
+ @Nonnull
+ @Override
+ public Collection<RecipeMap<?>> getAvailableRecipeMaps() {
+ return Arrays.asList(
+ RecipeMaps.compressorRecipes,
+ RecipeMaps.latheRecipes,
+ RecipeMaps.polarizerRecipes,
+ RecipeMaps.fermentingRecipes,
+ RecipeMaps.fluidExtractionRecipes,
+ RecipeMaps.extractorRecipes,
+ RecipeMaps.laserEngraverRecipes,
+ RecipeMaps.autoclaveRecipes,
+ RecipeMaps.fluidSolidifierRecipes);
+ }
+
+ @Override
+ public int getRecipeCatalystPriority() {
+ return -10;
+ }
+
+ private static RecipeMap<?> getRecipeMap(int aMode) {
+ if (aMode == MODE_COMPRESSOR) {
+ return RecipeMaps.compressorRecipes;
+ } else if (aMode == MODE_LATHE) {
+ return RecipeMaps.latheRecipes;
+ } else if (aMode == MODE_MAGNETIC) {
+ return RecipeMaps.polarizerRecipes;
+ } else if (aMode == MODE_FERMENTER) {
+ return RecipeMaps.fermentingRecipes;
+ } else if (aMode == MODE_FLUIDEXTRACT) {
+ return RecipeMaps.fluidExtractionRecipes;
+ } else if (aMode == MODE_EXTRACTOR) {
+ return RecipeMaps.extractorRecipes;
+ } else if (aMode == MODE_LASER) {
+ return RecipeMaps.laserEngraverRecipes;
+ } else if (aMode == MODE_AUTOCLAVE) {
+ return RecipeMaps.autoclaveRecipes;
+ } else if (aMode == MODE_FLUIDSOLIDIFY) {
+ return RecipeMaps.fluidSolidifierRecipes;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic() {
+
+ private ItemStack lastCircuit = null;
+
+ @Nonnull
+ @Override
+ protected Stream<GT_Recipe> findRecipeMatches(@Nullable RecipeMap<?> map) {
+ ItemStack circuit = getCircuit(inputItems);
+ if (circuit == null) {
+ return Stream.empty();
+ }
+ if (!GT_Utility.areStacksEqual(circuit, lastCircuit)) {
+ lastRecipe = null;
+ lastCircuit = circuit;
+ }
+ RecipeMap<?> foundMap = getRecipeMap(getCircuitID(circuit));
+ if (foundMap == null) {
+ return Stream.empty();
+ }
+ return super.findRecipeMatches(foundMap);
+ }
+ }.setSpeedBonus(1F / 3.5F)
+ .setEuModifier(0.8F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ public void onModeChangeByScrewdriver(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+ if (mInternalMode < 2) {
+ mInternalMode++;
+ } else {
+ mInternalMode = 0;
+ }
+ String mModeString = (mInternalMode == 0 ? "Metal"
+ : mInternalMode == 1 ? "Fluid" : mInternalMode == 2 ? "Misc." : "null");
+ PlayerUtils.messagePlayer(aPlayer, "Multi-Machine is now in " + mModeString + " mode.");
+ mLastRecipe = null;
+ }
+
+ @Override
+ public String[] getInfoData() {
+ String[] data = super.getInfoData();
+ ArrayList<String> mInfo = new ArrayList<>(Arrays.asList(data));
+ String mode;
+ if (mInternalMode == 0) {
+ mode = StatCollector.translateToLocal("GTPP.multiblock.multimachine.metal");
+ } else if (mInternalMode == 1) {
+ mode = StatCollector.translateToLocal("GTPP.multiblock.multimachine.fluid");
+ } else {
+ mode = StatCollector.translateToLocal("GTPP.multiblock.multimachine.misc");
+ }
+ mInfo.add(mode);
+ return mInfo.toArray(new String[0]);
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ aNBT.setInteger("mInternalMode", mInternalMode);
+ super.saveNBTData(aNBT);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ this.mInternalMode = aNBT.getInteger("mInternalMode");
+ super.loadNBTData(aNBT);
+ }
+
+ @Override
+ public boolean isInputSeparationEnabled() {
+ return true;
+ }
+
+ @Override
+ public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y,
+ int z) {
+ super.getWailaNBTData(player, tile, tag, world, x, y, z);
+ tag.setInteger("mode", mInternalMode);
+ }
+
+ @Override
+ protected CheckRecipeResult doCheckRecipe() {
+
+ if (mInternalMode != 2 || !isInputSeparationEnabled()) {
+ return super.doCheckRecipe();
+ } else {
+ CheckRecipeResult result = CheckRecipeResultRegistry.NO_RECIPE;
+
+ // check crafting input hatches first
+ if (supportsCraftingMEBuffer()) {
+ for (IDualInputHatch dualInputHatch : mDualInputHatches) {
+ for (var it = dualInputHatch.inventories(); it.hasNext();) {
+ IDualInputInventory slot = it.next();
+ processingLogic.setInputItems(slot.getItemInputs());
+ processingLogic.setInputFluids(slot.getFluidInputs());
+ CheckRecipeResult foundResult = processingLogic.process();
+ if (foundResult.wasSuccessful()) {
+ return foundResult;
+ }
+ if (foundResult != CheckRecipeResultRegistry.NO_RECIPE) {
+ // Recipe failed in interesting way, so remember that and continue searching
+ result = foundResult;
+ }
+ }
+ }
+ }
+
+ // Logic for GT_MetaTileEntity_Hatch_Solidifier
+ for (GT_MetaTileEntity_Hatch_Input solidifierHatch : mInputHatches) {
+ if (solidifierHatch instanceof GT_MetaTileEntity_Hatch_Solidifier) {
+ ItemStack mold = ((GT_MetaTileEntity_Hatch_Solidifier) solidifierHatch).getMold();
+ FluidStack fluid = solidifierHatch.getFluid();
+
+ if (mold != null && fluid != null) {
+ List<ItemStack> inputItems = new ArrayList<>();
+ inputItems.add(mold);
+ inputItems.add(ItemUtils.getGregtechCircuit(22));
+
+ processingLogic.setInputItems(inputItems.toArray(new ItemStack[0]));
+ processingLogic.setInputFluids(fluid);
+
+ CheckRecipeResult foundResult = processingLogic.process();
+ if (foundResult.wasSuccessful()) {
+ return foundResult;
+ }
+ if (foundResult != CheckRecipeResultRegistry.NO_RECIPE) {
+ // Recipe failed in interesting way, so remember that and continue searching
+ result = foundResult;
+ }
+ }
+ }
+ }
+ processingLogic.clear();
+ processingLogic.setInputFluids(getStoredFluids());
+ // Default logic
+ for (GT_MetaTileEntity_Hatch_InputBus bus : mInputBusses) {
+ if (bus instanceof GT_MetaTileEntity_Hatch_CraftingInput_ME) {
+ continue;
+ }
+ List<ItemStack> inputItems = new ArrayList<>();
+ for (int i = bus.getSizeInventory() - 1; i >= 0; i--) {
+ ItemStack stored = bus.getStackInSlot(i);
+ if (stored != null) {
+ inputItems.add(stored);
+ }
+ }
+ if (canUseControllerSlotForRecipe() && getControllerSlot() != null) {
+ inputItems.add(getControllerSlot());
+ }
+ processingLogic.setInputItems(inputItems.toArray(new ItemStack[0]));
+ CheckRecipeResult foundResult = processingLogic.process();
+ if (foundResult.wasSuccessful()) {
+ return foundResult;
+ }
+ if (foundResult != CheckRecipeResultRegistry.NO_RECIPE) {
+ // Recipe failed in interesting way, so remember that and continue searching
+ result = foundResult;
+ }
+ }
+
+ return result;
+ }
+ }
+
+ @Override
+ public ArrayList<FluidStack> getStoredFluids() {
+ ArrayList<FluidStack> rList = new ArrayList<>();
+ for (GT_MetaTileEntity_Hatch_Input tHatch : filterValidMTEs(mInputHatches)) {
+ if (tHatch instanceof GT_MetaTileEntity_Hatch_Solidifier) {
+ continue;
+ }
+
+ setHatchRecipeMap(tHatch);
+ if (tHatch instanceof GT_MetaTileEntity_Hatch_MultiInput) {
+ for (FluidStack tFluid : ((GT_MetaTileEntity_Hatch_MultiInput) tHatch).getStoredFluid()) {
+ if (tFluid != null) {
+ rList.add(tFluid);
+ }
+ }
+ } else if (tHatch instanceof GT_MetaTileEntity_Hatch_Input_ME) {
+ if (tHatch.isValid()) {
+ for (FluidStack fluidStack : ((GT_MetaTileEntity_Hatch_Input_ME) tHatch).getStoredFluids()) {
+ if (fluidStack == null) continue;
+ rList.add(fluidStack);
+ }
+ }
+ } else {
+ if (tHatch.getFillableStack() != null) {
+ rList.add(tHatch.getFillableStack());
+ }
+ }
+ }
+
+ return rList;
+ }
+
+ @Override
+ public void getWailaBody(ItemStack itemStack, List<String> currentTip, IWailaDataAccessor accessor,
+ IWailaConfigHandler config) {
+ super.getWailaBody(itemStack, currentTip, accessor, config);
+ final NBTTagCompound tag = accessor.getNBTData();
+ if (tag.hasKey("mode")) {
+ currentTip.add("Mode: " + EnumChatFormatting.YELLOW + switch (tag.getInteger("mode")) {
+ case 1 -> "Fluid";
+ case 2 -> "Misc";
+ default -> "Metal";
+ } + EnumChatFormatting.RESET);
+ }
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialPlatePress.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialPlatePress.java
new file mode 100644
index 0000000000..972cf492b6
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialPlatePress.java
@@ -0,0 +1,218 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import javax.annotation.Nonnull;
+
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.SoundResource;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.minecraft.PlayerUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_IndustrialPlatePress
+ extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialPlatePress> implements ISurvivalConstructable {
+
+ private boolean mFormingMode = false;
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialPlatePress> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_IndustrialPlatePress(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_IndustrialPlatePress(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IndustrialPlatePress(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Bending Machine, Forming Press";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for Advanced Bending & Forming")
+ .addInfo("500% faster than using single block machines of the same voltage")
+ .addInfo("Processes four items per voltage tier")
+ .addInfo("Circuit for recipe goes in the Input Bus")
+ .addInfo("Each Input Bus can have a different Circuit/Shape!")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 3, 3, true)
+ .addController("Front Center")
+ .addCasingInfoMin("Material Press Machine Casings", 6, false)
+ .addInputBus("Any Casing", 1)
+ .addOutputBus("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialPlatePress> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialPlatePress>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC" }, { "C~C", "C-C", "CCC" }, { "CCC", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialPlatePress.class)
+ .atLeast(InputBus, OutputBus, Maintenance, Energy, Muffler)
+ .casingIndex(50)
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasingsMisc, 4))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 1, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ return checkPiece(mName, 1, 1, 0) && mCasing >= 6 && checkHatch();
+ }
+
+ @Override
+ protected SoundResource getProcessStartSound() {
+ return SoundResource.IC2_MACHINES_COMPRESSOR_OP;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return 50;
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return mFormingMode ? RecipeMaps.formingPressRecipes : RecipeMaps.benderRecipes;
+ }
+
+ @Nonnull
+ @Override
+ public Collection<RecipeMap<?>> getAvailableRecipeMaps() {
+ return Arrays.asList(RecipeMaps.formingPressRecipes, RecipeMaps.benderRecipes);
+ }
+
+ @Override
+ public int getRecipeCatalystPriority() {
+ return -1;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic().setSpeedBonus(1F / 6F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return (4 * GT_Utility.getTier(this.getMaxInputVoltage()));
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ if (this.mFormingMode) return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialPlatePress_ModeForming;
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialPlatePress_ModeBending;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ aNBT.setBoolean("mFormingMode", mFormingMode);
+ super.saveNBTData(aNBT);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ mFormingMode = aNBT.getBoolean("mFormingMode");
+ super.loadNBTData(aNBT);
+ }
+
+ @Override
+ public void onModeChangeByScrewdriver(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+ mFormingMode = !mFormingMode;
+ if (mFormingMode) {
+ PlayerUtils.messagePlayer(aPlayer, "Now running in Forming Press Mode.");
+ } else {
+ PlayerUtils.messagePlayer(aPlayer, "Now running in Bending Mode.");
+ }
+ mLastRecipe = null;
+ }
+
+ @Override
+ public boolean isInputSeparationEnabled() {
+ return true;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialSifter.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialSifter.java
new file mode 100644
index 0000000000..e4dd3d11ba
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialSifter.java
@@ -0,0 +1,209 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import java.util.Random;
+
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_IndustrialSifter
+ extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialSifter> implements ISurvivalConstructable {
+
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialSifter> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_IndustrialSifter(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_IndustrialSifter(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IndustrialSifter(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Sifter";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Industrial Sifter")
+ .addInfo("400% faster than single-block machines of the same voltage")
+ .addInfo("Only uses 75% of the EU/t normally required")
+ .addInfo("Processes four items per voltage tier")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(5, 3, 5, false)
+ .addController("Bottom Center")
+ .addCasingInfoMin("Sieve Grate", 18, false)
+ .addCasingInfoMin("Sieve Casings", 35, false)
+ .addInputBus("Any Casing", 1)
+ .addOutputBus("Any Casing", 1)
+ .addInputHatch("Any Casing", 1)
+ .addOutputHatch("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialSifter> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialSifter>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCCCC", "CMMMC", "CMMMC", "CMMMC", "CCCCC" },
+ { "CCCCC", "CMMMC", "CMMMC", "CMMMC", "CCCCC" },
+ { "CC~CC", "CCCCC", "CCCCC", "CCCCC", "CCCCC" }, }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialSifter.class)
+ .atLeast(InputBus, OutputBus, Maintenance, Energy, Muffler, InputHatch, OutputHatch)
+ .casingIndex(TAE.GTPP_INDEX(21))
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings2Misc, 5))))
+ .addElement('M', ofBlock(ModBlocks.blockCasings2Misc, 6))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 2, 2, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 2, 2, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ return checkPiece(mName, 2, 2, 0) && mCasing >= 35 && checkHatch();
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return TAE.GTPP_INDEX(21);
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return RecipeMaps.sifterRecipes;
+ }
+
+ @Override
+ public int getRecipeCatalystPriority() {
+ return -1;
+ }
+
+ @Override
+ public void onPreTick(final IGregTechTileEntity aBaseMetaTileEntity, final long aTick) {
+ super.onPreTick(aBaseMetaTileEntity, aTick);
+ if ((aBaseMetaTileEntity.isClientSide()) && (aBaseMetaTileEntity.isActive())
+ && (aBaseMetaTileEntity.getFrontFacing() != ForgeDirection.UP)
+ && (aBaseMetaTileEntity.getCoverIDAtSide(ForgeDirection.UP) == 0)
+ && (!aBaseMetaTileEntity.getOpacityAtSide(ForgeDirection.UP))) {
+ final Random tRandom = aBaseMetaTileEntity.getWorld().rand;
+ if (tRandom.nextFloat() > 0.4) return;
+
+ final int xDir = aBaseMetaTileEntity.getBackFacing().offsetX * 2;
+ final int zDir = aBaseMetaTileEntity.getBackFacing().offsetZ * 2;
+
+ aBaseMetaTileEntity.getWorld()
+ .spawnParticle(
+ "smoke",
+ (aBaseMetaTileEntity.getXCoord() + xDir + 2.1F) - (tRandom.nextFloat() * 3.2F),
+ aBaseMetaTileEntity.getYCoord() + 2.5f + (tRandom.nextFloat() * 1.2F),
+ (aBaseMetaTileEntity.getZCoord() + zDir + 2.1F) - (tRandom.nextFloat() * 3.2F),
+ 0.0,
+ 0.0,
+ 0.0);
+ }
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic().setSpeedBonus(1F / 5F)
+ .setEuModifier(0.75F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return (4 * GT_Utility.getTier(this.getMaxInputVoltage()));
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialSifter;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public boolean isOverclockerUpgradable() {
+ return true;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialThermalCentrifuge.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialThermalCentrifuge.java
new file mode 100644
index 0000000000..14ff4ebb6d
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialThermalCentrifuge.java
@@ -0,0 +1,184 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import net.minecraft.block.Block;
+import net.minecraft.item.ItemStack;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.GregTech_API;
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_IndustrialThermalCentrifuge extends
+ GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialThermalCentrifuge> implements ISurvivalConstructable {
+
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialThermalCentrifuge> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_IndustrialThermalCentrifuge(final int aID, final String aName,
+ final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_IndustrialThermalCentrifuge(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IndustrialThermalCentrifuge(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Thermal Centrifuge";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Industrial Thermal Centrifuge")
+ .addInfo("150% faster than using single block machines of the same voltage")
+ .addInfo("Only uses 80% of the EU/t normally required")
+ .addInfo("Processes eight items per voltage tier")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 2, 3, false)
+ .addController("Front Center")
+ .addCasingInfoMin("Thermal Processing Casings/Noise Hazard Sign Blocks", 8, false)
+ .addInputBus("Bottom Casing", 1)
+ .addOutputBus("Bottom Casing", 1)
+ .addEnergyHatch("Bottom Casing", 1)
+ .addMaintenanceHatch("Bottom Casing", 1)
+ .addMufflerHatch("Bottom Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialThermalCentrifuge> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialThermalCentrifuge>builder()
+ .addShape(mName, transpose(new String[][] { { "X~X", "XXX", "XXX" }, { "CCC", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ ofChain(
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialThermalCentrifuge.class)
+ .atLeast(InputBus, OutputBus, Maintenance, Energy, Muffler)
+ .casingIndex(getCasingTextureIndex())
+ .dot(1)
+ .build(),
+ onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings2Misc, 0)),
+ onElementPass(x -> ++x.mCasing, ofBlock(GregTech_API.sBlockCasings3, 9))))
+ .addElement(
+ 'X',
+ ofChain(
+ onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings2Misc, 0)),
+ onElementPass(x -> ++x.mCasing, ofBlock(GregTech_API.sBlockCasings3, 9))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 0, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 0, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ return checkPiece(mName, 1, 0, 0) && mCasing >= 8 && checkHatch();
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return getCasingTextureIndex();
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return RecipeMaps.thermalCentrifugeRecipes;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic().setSpeedBonus(1F / 2.5F)
+ .setEuModifier(0.8F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return (8 * GT_Utility.getTier(this.getMaxInputVoltage()));
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialThermalCentrifuge;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ public Block getCasingBlock() {
+ return ModBlocks.blockCasings2Misc;
+ }
+
+ public byte getCasingMeta() {
+ return 0;
+ }
+
+ public byte getCasingTextureIndex() {
+ return (byte) TAE.GTPP_INDEX(16);
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialVacuumFreezer.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialVacuumFreezer.java
new file mode 100644
index 0000000000..aba508e183
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialVacuumFreezer.java
@@ -0,0 +1,261 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+import static gregtech.api.util.GT_Utility.filterValidMTEs;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.fluids.FluidStack;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.shutdown.ShutDownReasonRegistry;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.minecraft.FluidUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GT_MetaTileEntity_Hatch_CustomFluidBase;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_IndustrialVacuumFreezer extends
+ GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialVacuumFreezer> implements ISurvivalConstructable {
+
+ public static int CASING_TEXTURE_ID;
+ public static String mCryoFuelName = "Gelid Cryotheum";
+ public static String mCasingName = "Advanced Cryogenic Casing";
+ public static String mHatchName = "Cryotheum Hatch";
+ public static FluidStack mFuelStack;
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialVacuumFreezer> STRUCTURE_DEFINITION = null;
+
+ private final ArrayList<GT_MetaTileEntity_Hatch_CustomFluidBase> mCryotheumHatches = new ArrayList<>();
+
+ public GregtechMetaTileEntity_IndustrialVacuumFreezer(final int aID, final String aName,
+ final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ mFuelStack = FluidUtils.getFluidStack("cryotheum", 1);
+ CASING_TEXTURE_ID = TAE.getIndexFromPage(2, 10);
+ }
+
+ public GregtechMetaTileEntity_IndustrialVacuumFreezer(final String aName) {
+ super(aName);
+ mFuelStack = FluidUtils.getFluidStack("cryotheum", 1);
+ CASING_TEXTURE_ID = TAE.getIndexFromPage(2, 10);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return (IMetaTileEntity) new GregtechMetaTileEntity_IndustrialVacuumFreezer(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Vacuum Freezer";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Factory Grade Advanced Vacuum Freezer")
+ .addInfo("Speed: +100% | EU Usage: 100% | Parallel: 4")
+ .addInfo("Consumes 20L of " + mCryoFuelName + "/s during operation")
+ .addInfo("Constructed exactly the same as a normal Vacuum Freezer")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 3, 3, true)
+ .addController("Front Center")
+ .addCasingInfoMin(mCasingName, 10, false)
+ .addInputBus("Any Casing", 1)
+ .addOutputBus("Any Casing", 1)
+ .addInputHatch("Any Casing", 1)
+ .addOutputHatch("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addOtherStructurePart(mHatchName, "Any Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialVacuumFreezer> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialVacuumFreezer>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC" }, { "C~C", "C-C", "CCC" }, { "CCC", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ ofChain(
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialVacuumFreezer.class)
+ .adder(GregtechMetaTileEntity_IndustrialVacuumFreezer::addCryotheumHatch)
+ .hatchId(967)
+ .shouldReject(t -> !t.mCryotheumHatches.isEmpty())
+ .casingIndex(CASING_TEXTURE_ID)
+ .dot(1)
+ .build(),
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialVacuumFreezer.class)
+ .atLeast(InputBus, OutputBus, Maintenance, Energy, Muffler, InputHatch, OutputHatch)
+ .casingIndex(CASING_TEXTURE_ID)
+ .dot(1)
+ .build(),
+ onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings3Misc, 10))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 1, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ mCryotheumHatches.clear();
+ return checkPiece(mName, 1, 1, 0) && mCasing >= 10 && checkHatch();
+ }
+
+ @Override
+ public boolean checkHatch() {
+ return super.checkHatch() && !mCryotheumHatches.isEmpty();
+ }
+
+ private boolean addCryotheumHatch(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) {
+ if (aTileEntity == null) {
+ return false;
+ } else {
+ IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+ if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_CustomFluidBase
+ && aMetaTileEntity.getBaseMetaTileEntity()
+ .getMetaTileID() == 967) {
+ return addToMachineListInternal(mCryotheumHatches, aTileEntity, aBaseCasingIndex);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void updateSlots() {
+ for (GT_MetaTileEntity_Hatch_CustomFluidBase tHatch : filterValidMTEs(mCryotheumHatches)) tHatch.updateSlots();
+ super.updateSlots();
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return CASING_TEXTURE_ID;
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return GTPPRecipeMaps.advancedFreezerRecipes;
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(final ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic().setSpeedBonus(1F / 2F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 4;
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialVacuumFreezer;
+ }
+
+ @Override
+ public int getDamageToComponent(final ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ private int mGraceTimer = 2;
+
+ @Override
+ public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {
+ /*
+ * if (this.getBaseMetaTileEntity().isActive()) { if (!this.depleteInput(mFuelStack.copy())) {
+ * this.getBaseMetaTileEntity().setActive(false); } }
+ */
+ super.onPostTick(aBaseMetaTileEntity, aTick);
+
+ if (this.mStartUpCheck < 0) {
+ if (this.mMaxProgresstime > 0 && this.mProgresstime != 0 || this.getBaseMetaTileEntity()
+ .hasWorkJustBeenEnabled()) {
+ if (aTick % 10 == 0 || this.getBaseMetaTileEntity()
+ .hasWorkJustBeenEnabled()) {
+ if (!this.depleteInputFromRestrictedHatches(this.mCryotheumHatches, 10)) {
+ if (mGraceTimer-- == 0) {
+ this.causeMaintenanceIssue();
+ this.stopMachine(
+ ShutDownReasonRegistry
+ .outOfFluid(Objects.requireNonNull(FluidUtils.getFluidStack("cryotheum", 20))));
+ mGraceTimer = 2;
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialWashPlant.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialWashPlant.java
new file mode 100644
index 0000000000..a12db63f4e
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialWashPlant.java
@@ -0,0 +1,372 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.isAir;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlockAnyMeta;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import javax.annotation.Nonnull;
+
+import net.minecraft.block.Block;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.init.Blocks;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.common.util.ForgeDirection;
+import net.minecraftforge.fluids.FluidStack;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits;
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.recipe.check.SimpleCheckRecipeResult;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.api.objects.Logger;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.minecraft.FluidUtils;
+import gtPlusPlus.core.util.minecraft.PlayerUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+import ic2.core.init.BlocksItems;
+import ic2.core.init.InternalName;
+
+public class GregtechMetaTileEntity_IndustrialWashPlant
+ extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialWashPlant> implements ISurvivalConstructable {
+
+ private int mMode = 0;
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialWashPlant> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_IndustrialWashPlant(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_IndustrialWashPlant(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IndustrialWashPlant(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Ore Washer, Simple Washer, Chemical Bath";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Industrial Wash Plant")
+ .addInfo("Can be configured with a screwdriver to also do Simple Washer and process Chemical Bathing")
+ .addInfo("400% faster than using single block machines of the same voltage")
+ .addInfo("Processes four item per voltage tier")
+ .addInfo("Always requires an Input Hatch full of water to refill structure")
+ .addInfo("Need to be filled with water.")
+ .addInfo("Will automatically fill water from input hatch.")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(5, 3, 7, true)
+ .addController("Front Center")
+ .addCasingInfoMin("Wash Plant Casings", 40, false)
+ .addInputBus("Any Casing", 1)
+ .addOutputBus("Any Casing", 1)
+ .addInputHatch("Any Casing", 1)
+ .addOutputHatch("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialWashPlant> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialWashPlant>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCCCC", "CwwwC", "CwwwC", "CwwwC", "CwwwC", "CwwwC", "CCCCC" },
+ { "CC~CC", "CwwwC", "CwwwC", "CwwwC", "CwwwC", "CwwwC", "CCCCC" },
+ { "CCCCC", "CCCCC", "CCCCC", "CCCCC", "CCCCC", "CCCCC", "CCCCC" }, }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialWashPlant.class)
+ .atLeast(InputBus, InputHatch, OutputHatch, OutputBus, Maintenance, Energy, Muffler)
+ .casingIndex(getCasingTextureIndex())
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(getCasingBlock(), getCasingMeta()))))
+ .addElement(
+ 'w',
+ ofChain(
+ isAir(),
+ ofBlockAnyMeta(Blocks.water),
+ ofBlockAnyMeta(Blocks.flowing_water),
+ ofBlockAnyMeta(BlocksItems.getFluidBlock(InternalName.fluidDistilledWater))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 2, 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 2, 1, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ return checkPiece(mName, 2, 1, 0) && mCasing >= 40 && checkHatch();
+ }
+
+ @Override
+ protected IAlignmentLimits getInitialAlignmentLimits() {
+ // don't rotate a washer, water will flow out.
+ return (d, r, f) -> d.offsetY == 0 && r.isNotRotated() && !f.isVerticallyFliped();
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return getCasingTextureIndex();
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return mMode == 0 ? RecipeMaps.oreWasherRecipes
+ : mMode == 1 ? GTPPRecipeMaps.simpleWasherRecipes : RecipeMaps.chemicalBathRecipes;
+ }
+
+ @Nonnull
+ @Override
+ public Collection<RecipeMap<?>> getAvailableRecipeMaps() {
+ return Arrays
+ .asList(RecipeMaps.oreWasherRecipes, GTPPRecipeMaps.simpleWasherRecipes, RecipeMaps.chemicalBathRecipes);
+ }
+
+ @Override
+ public int getRecipeCatalystPriority() {
+ return -10;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic() {
+
+ @NotNull
+ @Override
+ protected CheckRecipeResult validateRecipe(@NotNull GT_Recipe recipe) {
+ if (checkForWater()) {
+ return CheckRecipeResultRegistry.SUCCESSFUL;
+ }
+ return SimpleCheckRecipeResult.ofFailure("no_water");
+ }
+ }.setSpeedBonus(1F / 5F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return (4 * GT_Utility.getTier(this.getMaxInputVoltage()));
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ if (mMode == 2) return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialWashPlant_ModeChemBath;
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialWashPlant_ModeWasher;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ public Block getCasingBlock() {
+ return ModBlocks.blockCasings2Misc;
+ }
+
+ public byte getCasingMeta() {
+ return 4;
+ }
+
+ public byte getCasingTextureIndex() {
+ return (byte) TAE.GTPP_INDEX(11);
+ }
+
+ public boolean checkForWater() {
+
+ // Get Facing direction
+ IGregTechTileEntity aBaseMetaTileEntity = this.getBaseMetaTileEntity();
+ int mDirectionX = aBaseMetaTileEntity.getBackFacing().offsetX;
+ int mCurrentDirectionX;
+ int mCurrentDirectionZ;
+ int mOffsetX_Lower = 0;
+ int mOffsetX_Upper = 0;
+ int mOffsetZ_Lower = 0;
+ int mOffsetZ_Upper = 0;
+
+ if (mDirectionX == 0) {
+ mCurrentDirectionX = 2;
+ mCurrentDirectionZ = 3;
+ mOffsetX_Lower = -2;
+ mOffsetX_Upper = 2;
+ mOffsetZ_Lower = -3;
+ mOffsetZ_Upper = 3;
+ } else {
+ mCurrentDirectionX = 3;
+ mCurrentDirectionZ = 2;
+ mOffsetX_Lower = -3;
+ mOffsetX_Upper = 3;
+ mOffsetZ_Lower = -2;
+ mOffsetZ_Upper = 2;
+ }
+
+ // if (aBaseMetaTileEntity.fac)
+
+ final int xDir = aBaseMetaTileEntity.getBackFacing().offsetX * mCurrentDirectionX;
+ final int zDir = aBaseMetaTileEntity.getBackFacing().offsetZ * mCurrentDirectionZ;
+
+ int tAmount = 0;
+ for (int i = mOffsetX_Lower + 1; i <= mOffsetX_Upper - 1; ++i) {
+ for (int j = mOffsetZ_Lower + 1; j <= mOffsetZ_Upper - 1; ++j) {
+ for (int h = 0; h < 2; ++h) {
+ Block tBlock = aBaseMetaTileEntity.getBlockOffset(xDir + i, h, zDir + j);
+ byte tMeta = aBaseMetaTileEntity.getMetaIDOffset(xDir + i, h, zDir + j);
+ if (tBlock == Blocks.air || tBlock == Blocks.flowing_water || tBlock == Blocks.water) {
+ if (this.getStoredFluids() != null) {
+ for (FluidStack stored : this.getStoredFluids()) {
+ if (stored.isFluidEqual(FluidUtils.getFluidStack("water", 1))) {
+ if (stored.amount >= 1000) {
+ // Utils.LOG_WARNING("Going to try swap an air block for water from inut bus.");
+ stored.amount -= 1000;
+ Block fluidUsed = null;
+ if (tBlock == Blocks.air || tBlock == Blocks.flowing_water) {
+ fluidUsed = Blocks.water;
+ }
+ if (tBlock == Blocks.water) {
+ fluidUsed = BlocksItems.getFluidBlock(InternalName.fluidDistilledWater);
+ }
+ aBaseMetaTileEntity.getWorld()
+ .setBlock(
+ aBaseMetaTileEntity.getXCoord() + xDir + i,
+ aBaseMetaTileEntity.getYCoord() + h,
+ aBaseMetaTileEntity.getZCoord() + zDir + j,
+ fluidUsed);
+ }
+ }
+ }
+ }
+ }
+ if (tBlock == Blocks.water) {
+ ++tAmount;
+ // Utils.LOG_WARNING("Found Water");
+ } else if (tBlock == BlocksItems.getFluidBlock(InternalName.fluidDistilledWater)) {
+ ++tAmount;
+ ++tAmount;
+ // Utils.LOG_WARNING("Found Distilled Water");
+ }
+ }
+ }
+ }
+
+ boolean isValidWater = tAmount >= 45;
+ if (isValidWater) {
+ Logger.WARNING("Filled structure.");
+ } else {
+ Logger.WARNING("Did not fill structure.");
+ }
+ return isValidWater;
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ aNBT.setInteger("mMode", mMode);
+ super.saveNBTData(aNBT);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ if (aNBT.hasKey("mChemicalMode")) {
+ boolean aTempMode = aNBT.getBoolean("mChemicalMode");
+ if (aTempMode) {
+ mMode = 2;
+ } else {
+ mMode = 0;
+ }
+ aNBT.removeTag("mChemicalMode");
+ }
+ if (aNBT.hasKey("mMode")) {
+ mMode = aNBT.getInteger("mMode");
+ }
+ super.loadNBTData(aNBT);
+ }
+
+ @Override
+ public void onModeChangeByScrewdriver(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+ mMode++;
+ if (mMode > 2) {
+ mMode = 0;
+ }
+ if (mMode == 0) {
+ PlayerUtils.messagePlayer(aPlayer, "Wash Plant is now running in Ore Washer Mode.");
+ } else if (mMode == 1) {
+ PlayerUtils.messagePlayer(aPlayer, "Wash Plant is now running in Simple Washer Mode.");
+ } else {
+ PlayerUtils.messagePlayer(aPlayer, "Wash Plant is now running in Chemical Bath Mode.");
+ }
+ mLastRecipe = null;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialWireMill.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialWireMill.java
new file mode 100644
index 0000000000..15ae5a96f8
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IndustrialWireMill.java
@@ -0,0 +1,215 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import net.minecraft.block.Block;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.ChatComponentTranslation;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.SoundResource;
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_IndustrialWireMill
+ extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialWireMill> implements ISurvivalConstructable {
+
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialWireMill> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_IndustrialWireMill(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ inputSeparation = true;
+ }
+
+ public GregtechMetaTileEntity_IndustrialWireMill(final String aName) {
+ super(aName);
+ inputSeparation = true;
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IndustrialWireMill(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Wiremill";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Industrial Wire Factory")
+ .addInfo("200% faster than using single block machines of the same voltage")
+ .addInfo("Only uses 75% of the EU/t normally required")
+ .addInfo("Processes four items per voltage tier")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 3, 5, true)
+ .addController("Front Center")
+ .addCasingInfoMin("Wire Factory Casings", 14, false)
+ .addInputBus("Any Casing", 1)
+ .addOutputBus("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialWireMill> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialWireMill>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC", "CCC", "CCC" }, { "C~C", "C-C", "C-C", "C-C", "CCC" },
+ { "CCC", "CCC", "CCC", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialWireMill.class)
+ .atLeast(InputBus, OutputBus, Maintenance, Energy, Muffler)
+ .casingIndex(getCasingTextureIndex())
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(getCasingBlock(), getCasingMeta()))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 1, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ return checkPiece(mName, 1, 1, 0) && mCasing >= 14 && checkHatch();
+ }
+
+ @Override
+ protected SoundResource getProcessStartSound() {
+ return SoundResource.IC2_MACHINES_RECYCLER_OP;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return TAE.GTPP_INDEX(6);
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return RecipeMaps.wiremillRecipes;
+ }
+
+ @Override
+ public int getRecipeCatalystPriority() {
+ return -1;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic().setSpeedBonus(1F / 3F)
+ .setEuModifier(0.75F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ public void onModeChangeByScrewdriver(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+ inputSeparation = !inputSeparation;
+ aPlayer.addChatMessage(
+ new ChatComponentTranslation(
+ inputSeparation ? "interaction.separateBusses.enabled" : "interaction.separateBusses.disabled"));
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ if (!aNBT.hasKey(INPUT_SEPARATION_NBT_KEY)) {
+ inputSeparation = aNBT.getBoolean("isBussesSeparate");
+ }
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return (4 * GT_Utility.getTier(this.getMaxInputVoltage()));
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialWireMill;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ public Block getCasingBlock() {
+ return ModBlocks.blockCasingsMisc;
+ }
+
+ public byte getCasingMeta() {
+ return 6;
+ }
+
+ public byte getCasingTextureIndex() {
+ return (byte) TAE.GTPP_INDEX(6);
+ }
+
+ @Override
+ public boolean supportsInputSeparation() {
+ return true;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IsaMill.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IsaMill.java
new file mode 100644
index 0000000000..c14cae9b88
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_IsaMill.java
@@ -0,0 +1,529 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+import static gregtech.api.util.GT_Utility.filterValidMTEs;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+import net.minecraft.block.Block;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.DamageSource;
+import net.minecraft.world.World;
+import net.minecraft.world.chunk.Chunk;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.recipe.check.SimpleCheckRecipeResult;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.api.objects.Logger;
+import gtPlusPlus.api.objects.data.AutoMap;
+import gtPlusPlus.api.objects.minecraft.BlockPos;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.item.chemistry.general.ItemGenericChemBase;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.math.MathUtils;
+import gtPlusPlus.core.util.minecraft.EntityUtils;
+import gtPlusPlus.core.util.minecraft.ItemUtils;
+import gtPlusPlus.core.util.minecraft.PlayerUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.nbthandlers.GT_MetaTileEntity_Hatch_MillingBalls;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock.CustomIcon;
+
+public class GregtechMetaTileEntity_IsaMill extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IsaMill>
+ implements ISurvivalConstructable {
+
+ protected boolean boostEu = false;
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_IsaMill> STRUCTURE_DEFINITION = null;
+
+ private static final IIconContainer frontFaceActive = new CustomIcon("iconsets/Grinder/GRINDER_ACTIVE5");
+ private static final IIconContainer frontFace = new CustomIcon("iconsets/Grinder/GRINDER5");
+
+ private final ArrayList<GT_MetaTileEntity_Hatch_MillingBalls> mMillingBallBuses = new ArrayList<>();
+ private static final DamageSource mIsaMillDamageSource = new DamageSource("gtpp.grinder").setDamageBypassesArmor();
+
+ public GregtechMetaTileEntity_IsaMill(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_IsaMill(String aName) {
+ super(aName);
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Large Grinding Machine")
+ .addInfo("Grind ores.")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 3, 7, false)
+ .addController("Front Center")
+ .addCasingInfoMin("IsaMill Exterior Casing", 40, false)
+ .addOtherStructurePart("IsaMill Gearbox", "5x, Inner Blocks")
+ .addOtherStructurePart("IsaMill Piping", "8x, ring around controller")
+ .addStructureInfo("IsaMill Pipings must not be obstructed in front (only air blocks)")
+ .addOtherStructurePart("Milling Ball Hatch", "Any Casing")
+ .addInputBus("Any Casing", 1)
+ .addOutputBus("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IsaMill> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IsaMill>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "DDD", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC" },
+ { "D~D", "CGC", "CGC", "CGC", "CGC", "CGC", "CCC" },
+ { "DDD", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ ofChain(
+ buildHatchAdder(GregtechMetaTileEntity_IsaMill.class)
+ .adder(GregtechMetaTileEntity_IsaMill::addMillingBallsHatch)
+ .hatchClass(GT_MetaTileEntity_Hatch_MillingBalls.class)
+ .shouldReject(t -> !t.mMillingBallBuses.isEmpty())
+ .casingIndex(getCasingTextureIndex())
+ .dot(1)
+ .build(),
+ buildHatchAdder(GregtechMetaTileEntity_IsaMill.class)
+ .atLeast(InputBus, OutputBus, InputHatch, OutputHatch, Maintenance, Energy, Muffler)
+ .casingIndex(getCasingTextureIndex())
+ .dot(1)
+ .build(),
+ onElementPass(x -> ++x.mCasing, ofBlock(getCasingBlock(), getCasingMeta()))))
+ .addElement('D', ofBlock(getIntakeBlock(), getIntakeMeta()))
+ .addElement('G', ofBlock(getGearboxBlock(), getGearboxMeta()))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 1, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ mMillingBallBuses.clear();
+ return checkPiece(mName, 1, 1, 0) && mCasing >= 48 - 8 && checkHatch();
+ }
+
+ @Override
+ public boolean checkHatch() {
+ return super.checkHatch() && mMillingBallBuses.size() == 1;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return frontFaceActive;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return frontFace;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return TAE.GTPP_INDEX(2);
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(ItemStack aStack) {
+ return getMaxEfficiency(aStack) > 0;
+ }
+
+ private boolean addMillingBallsHatch(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) {
+ if (aTileEntity == null) {
+ return false;
+ } else {
+ IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+ if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_MillingBalls) {
+ return addToMachineListInternal(mMillingBallBuses, aMetaTileEntity, aBaseCasingIndex);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean addToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) {
+
+ final IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+ if (aMetaTileEntity == null) {
+ return false;
+ }
+ if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_MillingBalls) {
+ log("Found GT_MetaTileEntity_Hatch_MillingBalls");
+ return addToMachineListInternal(mMillingBallBuses, aMetaTileEntity, aBaseCasingIndex);
+ }
+ return super.addToMachineList(aTileEntity, aBaseCasingIndex);
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return GTPPRecipeMaps.millingRecipes;
+ }
+
+ @Override
+ public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {
+ if (aBaseMetaTileEntity.isServerSide()) {
+ if (this.mUpdate == 1 || this.mStartUpCheck == 1) {
+ this.mMillingBallBuses.clear();
+ }
+ }
+ if (aTick % 20 == 0 && isMachineRunning()) {
+ checkForEntities(aBaseMetaTileEntity, aTick);
+ }
+ super.onPostTick(aBaseMetaTileEntity, aTick);
+ }
+
+ private final AutoMap<BlockPos> mFrontBlockPosCache = new AutoMap<>();
+
+ public void checkForEntities(IGregTechTileEntity aBaseMetaTileEntity, long aTime) {
+
+ if (aTime % 100 == 0) {
+ mFrontBlockPosCache.clear();
+ }
+ if (mFrontBlockPosCache.isEmpty()) {
+ ForgeDirection tSide = aBaseMetaTileEntity.getBackFacing();
+ int aTileX = aBaseMetaTileEntity.getXCoord();
+ int aTileY = aBaseMetaTileEntity.getYCoord();
+ int aTileZ = aBaseMetaTileEntity.getZCoord();
+ boolean xFacing = tSide.offsetX != 0;
+ boolean zFacing = tSide.offsetZ != 0;
+
+ // Check Casings
+ int aDepthOffset = (tSide == ForgeDirection.NORTH || tSide == ForgeDirection.WEST) ? 1 : -1;
+ for (int aHorizontalOffset = -1; aHorizontalOffset < 2; aHorizontalOffset++) {
+ for (int aVerticalOffset = -1; aVerticalOffset < 2; aVerticalOffset++) {
+ int aX = !xFacing ? (aTileX + aHorizontalOffset) : (aTileX + aDepthOffset);
+ int aY = aTileY + aVerticalOffset;
+ int aZ = !zFacing ? (aTileZ + aHorizontalOffset) : (aTileZ + aDepthOffset);
+ mFrontBlockPosCache.add(new BlockPos(aX, aY, aZ, aBaseMetaTileEntity.getWorld()));
+ }
+ }
+ }
+
+ AutoMap<EntityLivingBase> aEntities = getEntities(mFrontBlockPosCache, aBaseMetaTileEntity.getWorld());
+ if (!aEntities.isEmpty()) {
+ for (EntityLivingBase aFoundEntity : aEntities) {
+ if (aFoundEntity instanceof EntityPlayer aPlayer) {
+ if (PlayerUtils.isCreative(aPlayer) || !PlayerUtils.canTakeDamage(aPlayer)) {
+ continue;
+ } else {
+ if (aFoundEntity.getHealth() > 0) {
+ EntityUtils.doDamage(aFoundEntity, mIsaMillDamageSource, getPlayerDamageValue(aPlayer, 10));
+ if ((aBaseMetaTileEntity.isClientSide()) && (aBaseMetaTileEntity.isActive())) {
+ generateParticles(aFoundEntity);
+ }
+ }
+ }
+ } else if (aFoundEntity.getHealth() > 0) {
+ EntityUtils.doDamage(
+ aFoundEntity,
+ mIsaMillDamageSource,
+ Math.max(1, (int) (aFoundEntity.getMaxHealth() / 3)));
+ if ((aBaseMetaTileEntity.isClientSide()) && (aBaseMetaTileEntity.isActive())) {
+ generateParticles(aFoundEntity);
+ }
+ }
+ }
+ }
+ }
+
+ // 20 armor points add 80% damage reduction, more points add more damage reduction
+ private int getPlayerDamageValue(EntityPlayer player, int damage) {
+ int armorValue = player.getTotalArmorValue();
+ int reducedDamage = (int) (damage - damage * (armorValue * 0.04));
+ return Math.max(reducedDamage, 0);
+ }
+
+ private static AutoMap<EntityLivingBase> getEntities(AutoMap<BlockPos> aPositionsToCheck, World aWorld) {
+ AutoMap<EntityLivingBase> aEntities = new AutoMap<>();
+ HashSet<Chunk> aChunksToCheck = new HashSet<>();
+ if (!aPositionsToCheck.isEmpty()) {
+ Chunk aLocalChunk;
+ for (BlockPos aPos : aPositionsToCheck) {
+ aLocalChunk = aWorld.getChunkFromBlockCoords(aPos.xPos, aPos.zPos);
+ aChunksToCheck.add(aLocalChunk);
+ }
+ }
+ if (!aChunksToCheck.isEmpty()) {
+ AutoMap<EntityLivingBase> aEntitiesFound = new AutoMap<>();
+ for (Chunk aChunk : aChunksToCheck) {
+ if (aChunk.isChunkLoaded) {
+ List[] aEntityLists = aChunk.entityLists;
+ for (List aEntitySubList : aEntityLists) {
+ for (Object aEntity : aEntitySubList) {
+ if (aEntity instanceof EntityLivingBase aPlayer) {
+ aEntitiesFound.add(aPlayer);
+ }
+ }
+ }
+ }
+ }
+ if (!aEntitiesFound.isEmpty()) {
+ for (EntityLivingBase aEntity : aEntitiesFound) {
+ BlockPos aPlayerPos = EntityUtils.findBlockPosOfEntity(aEntity);
+ for (BlockPos aBlockSpaceToCheck : aPositionsToCheck) {
+ if (aBlockSpaceToCheck.equals(aPlayerPos)) {
+ aEntities.add(aEntity);
+ }
+ }
+ }
+ }
+ }
+ return aEntities;
+ }
+
+ private static void generateParticles(EntityLivingBase aEntity) {
+ BlockPos aPlayerPosBottom = EntityUtils.findBlockPosOfEntity(aEntity);
+ BlockPos aPlayerPosTop = aPlayerPosBottom.getUp();
+ AutoMap<BlockPos> aEntityPositions = new AutoMap<>();
+ aEntityPositions.add(aPlayerPosBottom);
+ aEntityPositions.add(aPlayerPosTop);
+ for (int i = 0; i < 64; i++) {
+ BlockPos aEffectPos = aEntityPositions.get(aEntity.height > 1f ? MathUtils.randInt(0, 1) : 0);
+ float aOffsetX = MathUtils.randFloat(-0.35f, 0.35f);
+ float aOffsetY = MathUtils.randFloat(-0.25f, 0.35f);
+ float aOffsetZ = MathUtils.randFloat(-0.35f, 0.35f);
+ aEntity.worldObj.spawnParticle(
+ "reddust",
+ aEffectPos.xPos + aOffsetX,
+ aEffectPos.yPos + 0.3f + aOffsetY,
+ aEffectPos.zPos + aOffsetZ,
+ 0.0D,
+ 0.0D,
+ 0.0D);
+ }
+ }
+
+ public Block getCasingBlock() {
+ return ModBlocks.blockCasings5Misc;
+ }
+
+ public byte getCasingMeta() {
+ return 0;
+ }
+
+ public Block getIntakeBlock() {
+ return ModBlocks.blockCasings5Misc;
+ }
+
+ public byte getIntakeMeta() {
+ return 1;
+ }
+
+ public Block getGearboxBlock() {
+ return ModBlocks.blockCasings5Misc;
+ }
+
+ public byte getGearboxMeta() {
+ return 2;
+ }
+
+ public byte getCasingTextureIndex() {
+ return 66;
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IsaMill(this.mName);
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ super.saveNBTData(aNBT);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return 1;
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIsaMill;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public String[] getExtraInfoData() {
+ return new String[] { "IsaMill Grinding Machine", "Current Efficiency: " + (mEfficiency / 100) + "%",
+ getIdealStatus() == getRepairStatus() ? "No Maintainance issues" : "Needs Maintainance" };
+ }
+
+ @Override
+ public boolean isGivingInformation() {
+ return true;
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Grinding Machine";
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 1;
+ }
+
+ /*
+ * Milling Ball Handling
+ */
+
+ @Override
+ public ArrayList<ItemStack> getStoredInputs() {
+ ArrayList<ItemStack> tItems = super.getStoredInputs();
+ for (GT_MetaTileEntity_Hatch_MillingBalls tHatch : filterValidMTEs(mMillingBallBuses)) {
+ AutoMap<ItemStack> aHatchContent = tHatch.getContentUsageSlots();
+ if (!aHatchContent.isEmpty()) {
+ tItems.addAll(aHatchContent);
+ }
+ }
+ return tItems;
+ }
+
+ public int getMaxBallDurability(ItemStack aStack) {
+ return ItemGenericChemBase.getMaxBallDurability(aStack);
+ }
+
+ private ItemStack findMillingBall(ItemStack[] aItemInputs) {
+ if (mMillingBallBuses.size() != 1) {
+ return null;
+ } else {
+ GT_MetaTileEntity_Hatch_MillingBalls aBus = mMillingBallBuses.get(0);
+ if (aBus != null) {
+ AutoMap<ItemStack> aAvailableItems = aBus.getContentUsageSlots();
+ if (!aAvailableItems.isEmpty()) {
+ for (final ItemStack aInput : aItemInputs) {
+ if (ItemUtils.isMillingBall(aInput)) {
+ for (ItemStack aBall : aAvailableItems) {
+ if (GT_Utility.areStacksEqual(aBall, aInput, true)) {
+ Logger.INFO("Found a valid milling ball to use.");
+ return aBall;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private void damageMillingBall(ItemStack aStack) {
+ if (MathUtils.randFloat(0, 10000000) / 10000000f < (1.2f - (0.2 * 1))) {
+ int damage = getMillingBallDamage(aStack) + 1;
+ log("damage milling ball " + damage);
+ if (damage >= getMaxBallDurability(aStack)) {
+ log("consuming milling ball");
+ aStack.stackSize -= 1;
+ } else {
+ setDamage(aStack, damage);
+ }
+ } else {
+ log("not damaging milling ball");
+ }
+ }
+
+ private int getMillingBallDamage(ItemStack aStack) {
+ return ItemGenericChemBase.getMillingBallDamage(aStack);
+ }
+
+ private void setDamage(ItemStack aStack, int aAmount) {
+ ItemGenericChemBase.setMillingBallDamage(aStack, aAmount);
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic() {
+
+ ItemStack millingBall;
+
+ @NotNull
+ @Override
+ protected CheckRecipeResult validateRecipe(@NotNull GT_Recipe recipe) {
+ millingBall = findMillingBall(inputItems);
+ if (millingBall == null) {
+ return SimpleCheckRecipeResult.ofFailure("no_milling_ball");
+ }
+ return CheckRecipeResultRegistry.SUCCESSFUL;
+ }
+
+ @NotNull
+ @Override
+ public CheckRecipeResult process() {
+ CheckRecipeResult result = super.process();
+ if (result.wasSuccessful()) {
+ damageMillingBall(millingBall);
+ }
+ return result;
+ }
+ }.enablePerfectOverclock();
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_NuclearSaltProcessingPlant.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_NuclearSaltProcessingPlant.java
new file mode 100644
index 0000000000..6d1593bec9
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_NuclearSaltProcessingPlant.java
@@ -0,0 +1,224 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import net.minecraft.item.ItemStack;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.GregTech_API;
+import gregtech.api.enums.TAE;
+import gregtech.api.enums.Textures;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.metatileentity.MetaTileEntity;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+
+public class GregtechMetaTileEntity_NuclearSaltProcessingPlant extends
+ GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_NuclearSaltProcessingPlant> implements ISurvivalConstructable {
+
+ protected GT_Recipe lastRecipeToBuffer;
+ private int casing;
+ private static IStructureDefinition<GregtechMetaTileEntity_NuclearSaltProcessingPlant> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_NuclearSaltProcessingPlant(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_NuclearSaltProcessingPlant(String mName) {
+ super(mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Reactor Processing Unit, Cold Trap";
+ }
+
+ @Override
+ public MetaTileEntity newMetaEntity(IGregTechTileEntity tileEntity) {
+ return new GregtechMetaTileEntity_NuclearSaltProcessingPlant(this.mName);
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack itemStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiAutoCrafter;
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Nuclear Salt Processing Plant")
+ .addInfo("Processes depleted nuclear salts that come from the LFTR")
+ .addInfo("Handles the recipes of the Reactor Processor Unit and Cold Trap")
+ .addInfo("Only Thermally Insulated Casings can be replaced with hatches")
+ .addInfo("Mufflers on top, Energy Hatches on bottom, exactly 2 of each are required")
+ .addInfo("Maintenance Hatch goes on the back, opposite of the controller block")
+ .addInfo("Inputs go on the left side of the multi, outputs on the right side")
+ .addInfo("150% faster than using single block machines of the same voltage")
+ .addInfo("Processes two items per voltage tier")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 3, 3, true)
+ .addController("Front Center")
+ .addCasingInfoMin("IV Machine Casing", 58, false)
+ .addCasingInfoMin("Thermally Insulated Casing", 1, false)
+ .addInputBus("Left Half", 2)
+ .addInputHatch("Left Half", 2)
+ .addOutputBus("Right Half", 3)
+ .addOutputHatch("Right Half", 3)
+ .addMufflerHatch("Top Side, 2 Required", 4)
+ .addEnergyHatch("Bottom Side, 2 Required", 5)
+ .addMaintenanceHatch("Back Side, Opposite of Controller", 6)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return Textures.BlockIcons.OVERLAY_FRONT_DISASSEMBLER_ACTIVE;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return Textures.BlockIcons.OVERLAY_FRONT_DISASSEMBLER;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return TAE.getIndexFromPage(0, 10);
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_NuclearSaltProcessingPlant> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_NuclearSaltProcessingPlant>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "AAA AAA", "ADA ADA", "AAA AAA" },
+ { "ABBA ACCA", "B AAA C", "ABBA ACCA" }, { "ABBB~CCCA", "B C", "ABBBFCCCA" },
+ { "ABBA ACCA", "B AAA C", "ABBA ACCA" }, { "AAA AAA", "AEA AEA", "AAA AAA" } }))
+ .addElement('A', ofBlock(GregTech_API.sBlockCasings1, 5))
+ .addElement(
+ 'B',
+ buildHatchAdder(GregtechMetaTileEntity_NuclearSaltProcessingPlant.class)
+ .atLeast(InputBus, InputHatch)
+ .casingIndex(TAE.getIndexFromPage(0, 10))
+ .dot(2)
+ .buildAndChain(onElementPass(x -> ++x.casing, ofBlock(ModBlocks.blockSpecialMultiCasings, 8))))
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntity_NuclearSaltProcessingPlant.class)
+ .atLeast(OutputBus, OutputHatch)
+ .casingIndex(TAE.getIndexFromPage(0, 10))
+ .dot(3)
+ .buildAndChain(onElementPass(x -> ++x.casing, ofBlock(ModBlocks.blockSpecialMultiCasings, 8))))
+ .addElement(
+ 'D',
+ buildHatchAdder(GregtechMetaTileEntity_NuclearSaltProcessingPlant.class).atLeast(Muffler)
+ .casingIndex(TAE.getIndexFromPage(0, 10))
+ .dot(4)
+ .buildAndChain(onElementPass(x -> ++x.casing, ofBlock(ModBlocks.blockSpecialMultiCasings, 8))))
+ .addElement(
+ 'E',
+ buildHatchAdder(GregtechMetaTileEntity_NuclearSaltProcessingPlant.class).atLeast(Energy)
+ .casingIndex(TAE.getIndexFromPage(0, 10))
+ .dot(5)
+ .buildAndChain(onElementPass(x -> ++x.casing, ofBlock(ModBlocks.blockSpecialMultiCasings, 8))))
+ .addElement(
+ 'F',
+ buildHatchAdder(GregtechMetaTileEntity_NuclearSaltProcessingPlant.class).atLeast(Maintenance)
+ .casingIndex(TAE.getIndexFromPage(0, 10))
+ .dot(6)
+ .buildAndChain(onElementPass(x -> ++x.casing, ofBlock(ModBlocks.blockSpecialMultiCasings, 8))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack itemStack, boolean hintsOnly) {
+ buildPiece(mName, itemStack, hintsOnly, 4, 2, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack itemStack, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, itemStack, 4, 2, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity baseMetaTileEntity, ItemStack itemStack) {
+ casing = 0;
+ return checkPiece(mName, 4, 2, 0) && checkHatch();
+ }
+
+ @Override
+ public boolean checkHatch() {
+ return mEnergyHatches.size() == 2 && mMufflerHatches.size() == 2 && super.checkHatch();
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return GTPPRecipeMaps.nuclearSaltProcessingPlantRecipes;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic().setSpeedBonus(1F / 2.5F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 2 * (Math.max(1, GT_Utility.getTier(getMaxInputVoltage())));
+ }
+
+ @Override
+ public String[] getExtraInfoData() {
+ final String running = (this.mMaxProgresstime > 0 ? "Salt Plant running" : "Salt Plant stopped");
+ final String maintenance = (this.getIdealStatus() == this.getRepairStatus() ? "No Maintenance issues"
+ : "Needs Maintenance");
+ String tSpecialText;
+
+ if (lastRecipeToBuffer != null && lastRecipeToBuffer.mOutputs[0].getDisplayName() != null) {
+ tSpecialText = "Currently processing: " + lastRecipeToBuffer.mOutputs[0].getDisplayName();
+ } else {
+ tSpecialText = "Currently processing: Nothing";
+ }
+
+ return new String[] { "Nuclear Salt Processing Plant", running, maintenance, tSpecialText };
+ }
+
+ @Override
+ public boolean supportsInputSeparation() {
+ return true;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_SpargeTower.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_SpargeTower.java
new file mode 100644
index 0000000000..5f4203b99e
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/GregtechMetaTileEntity_SpargeTower.java
@@ -0,0 +1,507 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.isAir;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+import static gregtech.api.util.GT_StructureUtility.ofHatchAdder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.common.util.ForgeDirection;
+import net.minecraftforge.fluids.FluidStack;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits;
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.interfaces.IHatchElement;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.fluid.IFluidStore;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.GT_Utility;
+import gregtech.api.util.GasSpargingRecipe;
+import gregtech.api.util.GasSpargingRecipeMap;
+import gtPlusPlus.api.objects.Logger;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.math.MathUtils;
+import gtPlusPlus.core.util.minecraft.PlayerUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_SpargeTower extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_SpargeTower>
+ implements ISurvivalConstructable {
+
+ protected static final String STRUCTURE_PIECE_BASE = "base";
+ protected static final String STRUCTURE_PIECE_LAYER = "layer";
+ protected static final String STRUCTURE_PIECE_LAYER_HINT = "layerHint";
+ protected static final String STRUCTURE_PIECE_TOP_HINT = "topHint";
+ private static final IStructureDefinition<GregtechMetaTileEntity_SpargeTower> STRUCTURE_DEFINITION;
+
+ static {
+ IHatchElement<GregtechMetaTileEntity_SpargeTower> layeredOutputHatch = OutputHatch
+ .withCount(GregtechMetaTileEntity_SpargeTower::getCurrentLayerOutputHatchCount)
+ .withAdder(GregtechMetaTileEntity_SpargeTower::addLayerOutputHatch);
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_SpargeTower>builder()
+ .addShape(STRUCTURE_PIECE_BASE, transpose(new String[][] { { "b~b", "bbb", "bbb" }, }))
+ .addShape(STRUCTURE_PIECE_LAYER, transpose(new String[][] { { "lll", "lcl", "lll" } }))
+ .addShape(STRUCTURE_PIECE_LAYER_HINT, transpose(new String[][] { { "lll", "l-l", "lll" } }))
+ .addShape(STRUCTURE_PIECE_TOP_HINT, transpose(new String[][] { { "lll", "lll", "lll" } }))
+ .addElement(
+ 'b',
+ buildHatchAdder(GregtechMetaTileEntity_SpargeTower.class)
+ .atLeast(Energy, InputHatch, InputBus, Maintenance)
+ .disallowOnly(ForgeDirection.UP)
+ .casingIndex(getCasingIndex())
+ .dot(1)
+ .buildAndChain(
+ onElementPass(
+ GregtechMetaTileEntity_SpargeTower::onCasingFound,
+ ofBlock(ModBlocks.blockCasings5Misc, 4))))
+ .addElement(
+ 'l',
+ ofChain(
+ buildHatchAdder(GregtechMetaTileEntity_SpargeTower.class).atLeast(layeredOutputHatch)
+ .disallowOnly(ForgeDirection.UP, ForgeDirection.DOWN)
+ .casingIndex(getCasingIndex())
+ .dot(2)
+ .build(),
+ ofHatchAdder(GregtechMetaTileEntity_SpargeTower::addEnergyInputToMachineList, getCasingIndex(), 2),
+ ofHatchAdder(GregtechMetaTileEntity_SpargeTower::addMaintenanceToMachineList, getCasingIndex(), 2),
+ onElementPass(
+ GregtechMetaTileEntity_SpargeTower::onCasingFound,
+ ofBlock(ModBlocks.blockCasings5Misc, 4))))
+ .addElement(
+ 'c',
+ ofChain(
+ onElementPass(
+ t -> t.onTopLayerFound(false),
+ ofHatchAdder(GregtechMetaTileEntity_SpargeTower::addOutputToMachineList, getCasingIndex(), 3)),
+ onElementPass(
+ t -> t.onTopLayerFound(false),
+ ofHatchAdder(
+ GregtechMetaTileEntity_SpargeTower::addMaintenanceToMachineList,
+ getCasingIndex(),
+ 3)),
+ onElementPass(t -> t.onTopLayerFound(true), ofBlock(ModBlocks.blockCasings5Misc, 4)),
+ isAir()))
+ .build();
+ }
+
+ protected final List<List<GT_MetaTileEntity_Hatch_Output>> mOutputHatchesByLayer = new ArrayList<>();
+ protected int mHeight;
+ protected int mCasing;
+ protected boolean mTopLayerFound;
+
+ public GregtechMetaTileEntity_SpargeTower(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_SpargeTower(String aName) {
+ super(aName);
+ }
+
+ public static int getCasingIndex() {
+ return 68;
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_SpargeTower(this.mName);
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType("Gas Sparge Tower")
+ .addInfo("Controller block for the Sparging Tower")
+ .addInfo("Runs gases through depleted molten salts to extract precious fluids")
+ .addInfo("Works the same way as the Distillation Tower, but with a fixed height of 8")
+ .addInfo("Fluids are only put out at the correct height")
+ .addInfo("The correct height equals the slot number in the NEI recipe")
+ .addSeparator()
+ .beginStructureBlock(3, 8, 3, true)
+ .addController("Front bottom")
+ .addOtherStructurePart("Sparge Tower Exterior Casing", "45 (minimum)")
+ .addEnergyHatch("Any casing", 1, 2)
+ .addMaintenanceHatch("Any casing", 1, 2, 3)
+ .addInputHatch("2x Input Hatches (Any bottom layer casing)", 1)
+ .addOutputHatch("6x Output Hatches (At least one per layer except bottom layer)", 2, 3)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return getCasingIndex();
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ if (GTPPRecipeMaps.spargeTowerFakeRecipes.getAllRecipes()
+ .isEmpty()) {
+ generateRecipes();
+ }
+ return GTPPRecipeMaps.spargeTowerFakeRecipes;
+ }
+
+ private static boolean generateRecipes() {
+ for (GasSpargingRecipe aRecipe : GasSpargingRecipeMap.mRecipes) {
+ GT_Recipe newRecipe = new GT_Recipe(
+ false,
+ new ItemStack[] {},
+ new ItemStack[] {},
+ null,
+ null,
+ aRecipe.mFluidInputs.clone(),
+ new FluidStack[] {},
+ aRecipe.mDuration,
+ aRecipe.mEUt,
+ 0);
+ GTPPRecipeMaps.spargeTowerFakeRecipes.add(newRecipe);
+ }
+ return !GTPPRecipeMaps.spargeTowerFakeRecipes.getAllRecipes()
+ .isEmpty();
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ public @NotNull CheckRecipeResult checkProcessing() {
+ ArrayList<FluidStack> tFluidList = getStoredFluids();
+ long tVoltage = GT_Utility.roundUpVoltage(this.getMaxInputVoltage());
+ byte tTier = (byte) Math.max(0, GT_Utility.getTier(tVoltage));
+ FluidStack[] tFluids = tFluidList.toArray(new FluidStack[0]);
+ if (tFluids.length > 0) {
+ GT_Recipe tRecipe = getRecipeMap()
+ .findRecipe(getBaseMetaTileEntity(), false, gregtech.api.enums.GT_Values.V[tTier], tFluids);
+ if (tRecipe != null) {
+ FluidStack[] possibleOutputs = getPossibleByproductsOfSparge(
+ tRecipe.mFluidInputs[0],
+ tRecipe.mFluidInputs[1]).toArray(new FluidStack[0]);
+ if (canOutputAll(possibleOutputs) && tRecipe.isRecipeInputEqual(true, tFluids)) {
+ this.mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000);
+ this.mEfficiencyIncrease = 10000;
+
+ calculateOverclockedNessMulti((long) tRecipe.mEUt, tRecipe.mDuration, 1, tVoltage);
+ mMaxProgresstime = Math.max(1, mMaxProgresstime);
+ ArrayList<FluidStack> aFluidOutputs = getByproductsOfSparge(
+ tRecipe.mFluidInputs[0],
+ tRecipe.mFluidInputs[1]);
+ this.mOutputFluids = aFluidOutputs.toArray(new FluidStack[0]);
+ updateSlots();
+
+ if (lEUt > 0) {
+ lEUt = (-lEUt);
+ }
+
+ return CheckRecipeResultRegistry.SUCCESSFUL;
+ }
+ }
+ }
+ this.lEUt = 0;
+ this.mEfficiency = 0;
+ return CheckRecipeResultRegistry.NO_RECIPE;
+ }
+
+ private static List<FluidStack> getPossibleByproductsOfSparge(final FluidStack aSpargeGas,
+ final FluidStack aSpentFuel) {
+ GasSpargingRecipe aSpargeRecipe = GasSpargingRecipeMap.findRecipe(aSpargeGas, aSpentFuel);
+ ArrayList<FluidStack> aOutputGases = new ArrayList<>();
+ if (aSpargeRecipe == null) {
+ return aOutputGases;
+ }
+
+ aOutputGases.add(aSpargeRecipe.mOutputSpargedFuel.copy());
+ ArrayList<FluidStack> aTempMap = new ArrayList<>();
+ for (int i = 2; i < aSpargeRecipe.mFluidOutputs.length; i++) {
+ int aGasAmount = aSpargeRecipe.mMaxOutputQuantity[i - 2] / 100;
+ FluidStack aOutput = aSpargeRecipe.mFluidOutputs[i].copy();
+ FluidStack aSpargeOutput = null;
+ if (aGasAmount > 0) {
+ aSpargeOutput = new FluidStack(aOutput.getFluid(), aGasAmount);
+ }
+ aTempMap.add(aSpargeOutput);
+ }
+ aOutputGases.add(new FluidStack(aSpargeRecipe.mInputGas.getFluid(), aSpargeRecipe.mInputGas.amount));
+ aOutputGases.addAll(aTempMap);
+ return aOutputGases;
+ }
+
+ private static ArrayList<FluidStack> getByproductsOfSparge(final FluidStack aSpargeGas,
+ final FluidStack aSpentFuel) {
+ GasSpargingRecipe aSpargeRecipe = GasSpargingRecipeMap.findRecipe(aSpargeGas, aSpentFuel);
+ ArrayList<FluidStack> aOutputGases = new ArrayList<>();
+ if (aSpargeRecipe == null) {
+ Logger.INFO("Did not find sparge recipe!");
+ return aOutputGases;
+ }
+ int aSpargeGasAmount = aSpargeRecipe.mInputGas.amount;
+
+ aOutputGases.add(aSpargeRecipe.mOutputSpargedFuel.copy());
+ ArrayList<FluidStack> aTempMap = new ArrayList<>();
+ for (int i = 2; i < aSpargeRecipe.mFluidOutputs.length; i++) {
+ int aGasAmount = MathUtils.randInt(0, (aSpargeRecipe.mMaxOutputQuantity[i - 2] / 100));
+ FluidStack aOutput = aSpargeRecipe.mFluidOutputs[i].copy();
+ aSpargeGasAmount -= aGasAmount;
+ FluidStack aSpargeOutput = null;
+ if (aGasAmount > 0) {
+ aSpargeOutput = new FluidStack(aOutput.getFluid(), aGasAmount);
+ }
+ aTempMap.add(aSpargeOutput);
+ }
+ Logger.INFO("Sparge gas left: " + aSpargeGasAmount);
+ if (aSpargeGasAmount > 0) {
+ aOutputGases.add(new FluidStack(aSpargeRecipe.mInputGas.getFluid(), aSpargeGasAmount));
+ }
+ // Logger.INFO("Sparge Outputs: "+ItemUtils.getArrayStackNames(aTempMap));
+ aOutputGases.addAll(aTempMap);
+ Logger.INFO("Sparge output size: " + aOutputGases.size());
+ // Logger.INFO("Output of sparging: "+ItemUtils.getArrayStackNames(aOutputGases));
+ return aOutputGases;
+ }
+
+ protected void onCasingFound() {
+ mCasing++;
+ }
+
+ protected void onTopLayerFound(boolean aIsCasing) {
+ mTopLayerFound = true;
+ if (aIsCasing) {
+ onCasingFound();
+ }
+ }
+
+ protected int getCurrentLayerOutputHatchCount() {
+ return mOutputHatchesByLayer.size() < mHeight || mHeight <= 0 ? 0
+ : mOutputHatchesByLayer.get(mHeight - 1)
+ .size();
+ }
+
+ protected boolean addLayerOutputHatch(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) {
+ if (aTileEntity == null || aTileEntity.isDead()
+ || !(aTileEntity.getMetaTileEntity() instanceof GT_MetaTileEntity_Hatch_Output tHatch)) {
+ Logger.INFO("Bad Output Hatch");
+ return false;
+ }
+ while (mOutputHatchesByLayer.size() < mHeight) {
+ mOutputHatchesByLayer.add(new ArrayList<>());
+ }
+ tHatch.updateTexture(aBaseCasingIndex);
+ boolean addedHatch = mOutputHatchesByLayer.get(mHeight - 1)
+ .add(tHatch);
+ Logger.INFO("Added Hatch: " + addedHatch);
+ return addedHatch;
+ }
+
+ @Override
+ public List<? extends IFluidStore> getFluidOutputSlots(FluidStack[] toOutput) {
+ return getFluidOutputSlotsByLayer(toOutput, mOutputHatchesByLayer);
+ }
+
+ @Override
+ protected IAlignmentLimits getInitialAlignmentLimits() {
+ // don't rotate a freaking tower, it won't work
+ return (d, r, f) -> d.offsetY == 0 && r.isNotRotated() && !f.isVerticallyFliped();
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_SpargeTower> getStructureDefinition() {
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ // reset
+ mOutputHatchesByLayer.forEach(List::clear);
+ mHeight = 1;
+ mTopLayerFound = false;
+ mCasing = 0;
+
+ // check base
+ if (!checkPiece(STRUCTURE_PIECE_BASE, 1, 0, 0)) {
+ Logger.INFO("Bad Base. Height: " + mHeight);
+ return false;
+ }
+
+ // check each layer
+ while (mHeight < 8 && checkPiece(STRUCTURE_PIECE_LAYER, 1, mHeight, 0) && !mTopLayerFound) {
+ if (mOutputHatchesByLayer.get(mHeight - 1)
+ .isEmpty()) {
+ // layer without output hatch
+ Logger.INFO("Height: " + mHeight + " - Missing output on " + (mHeight - 1));
+ return false;
+ }
+ // not top
+ mHeight++;
+ }
+
+ // validate final invariants...
+ Logger.INFO("Height: " + mHeight);
+ Logger.INFO("Casings: " + mCasing);
+ Logger.INFO("Required: " + (7 * mHeight - 5));
+ Logger.INFO("Found Top: " + mTopLayerFound);
+ return mCasing >= 45 && mTopLayerFound && mMaintenanceHatches.size() == 1;
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerTick(ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ protected void addFluidOutputs(FluidStack[] mOutputFluids2) {
+ for (int i = 0; i < mOutputFluids2.length && i < mOutputHatchesByLayer.size(); i++) {
+ FluidStack tStack = mOutputFluids2[i] != null ? mOutputFluids2[i].copy() : null;
+ if (tStack == null) {
+ continue;
+ }
+ if (!dumpFluid(mOutputHatchesByLayer.get(i), tStack, true)) {
+ dumpFluid(mOutputHatchesByLayer.get(i), tStack, false);
+ }
+ }
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(STRUCTURE_PIECE_BASE, stackSize, hintsOnly, 1, 0, 0);
+ int tTotalHeight = 8; // min 2 output layer, so at least 1 + 2 height
+ for (int i = 1; i < tTotalHeight - 1; i++) {
+ buildPiece(STRUCTURE_PIECE_LAYER_HINT, stackSize, hintsOnly, 1, i, 0);
+ }
+ buildPiece(STRUCTURE_PIECE_TOP_HINT, stackSize, hintsOnly, 1, tTotalHeight - 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ mHeight = 0;
+ int built = survivialBuildPiece(STRUCTURE_PIECE_BASE, stackSize, 1, 0, 0, elementBudget, env, false, true);
+ if (built >= 0) return built;
+ int tTotalHeight = 8; // min 2 output layer, so at least 1 + 2 height
+ for (int i = 1; i < tTotalHeight - 1; i++) {
+ mHeight = i;
+ built = survivialBuildPiece(
+ STRUCTURE_PIECE_LAYER_HINT,
+ stackSize,
+ 1,
+ i,
+ 0,
+ elementBudget,
+ env,
+ false,
+ true);
+ if (built >= 0) return built;
+ }
+ mHeight = tTotalHeight - 1;
+ return survivialBuildPiece(
+ STRUCTURE_PIECE_TOP_HINT,
+ stackSize,
+ 1,
+ tTotalHeight - 1,
+ 0,
+ elementBudget,
+ env,
+ false,
+ true);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Gas Sparger";
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 1;
+ }
+
+ @Override
+ public boolean onPlungerRightClick(EntityPlayer aPlayer, ForgeDirection side, float aX, float aY, float aZ) {
+ int aLayerIndex = 0;
+ PlayerUtils
+ .messagePlayer(aPlayer, "Trying to clear " + mOutputHatchesByLayer.size() + " layers of output hatches.");
+ for (List<GT_MetaTileEntity_Hatch_Output> layer : this.mOutputHatchesByLayer) {
+ int aHatchIndex = 0;
+ for (GT_MetaTileEntity_Hatch_Output hatch : layer) {
+ if (hatch.mFluid != null) {
+ PlayerUtils.messagePlayer(
+ aPlayer,
+ "Clearing " + hatch.mFluid.amount
+ + "L of "
+ + hatch.mFluid.getLocalizedName()
+ + " from hatch "
+ + aHatchIndex
+ + " on layer "
+ + aLayerIndex
+ + ".");
+ hatch.mFluid = null;
+ }
+ aHatchIndex++;
+ }
+ aLayerIndex++;
+ }
+ return aLayerIndex > 0;
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ // Ensure that lEUt is negative from loaded NBT data, since this multi consumes EU
+ if (lEUt > 0) {
+ lEUt = (-lEUt);
+ }
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_DistillationTower.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_DistillationTower.java
new file mode 100644
index 0000000000..8296b8e7cb
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_DistillationTower.java
@@ -0,0 +1,491 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing.advanced;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.isAir;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+import static gregtech.api.util.GT_StructureUtility.ofHatchAdder;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.StatCollector;
+import net.minecraftforge.common.util.ForgeDirection;
+import net.minecraftforge.fluids.FluidStack;
+
+import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits;
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.GregTech_API;
+import gregtech.api.enums.Textures;
+import gregtech.api.interfaces.IHatchElement;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.fluid.IFluidStore;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_Output_ME;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.minecraft.ItemUtils;
+import gtPlusPlus.core.util.minecraft.PlayerUtils;
+import gtPlusPlus.xmod.gregtech.api.enums.GregtechItemList;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+
+public class GregtechMetaTileEntity_Adv_DistillationTower extends
+ GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_Adv_DistillationTower> implements ISurvivalConstructable {
+
+ private Mode mMode = Mode.DistillationTower;
+ private boolean mUpgraded = false;
+
+ protected static final String STRUCTURE_PIECE_BASE = "base";
+ protected static final String STRUCTURE_PIECE_LAYER = "layer";
+ protected static final String STRUCTURE_PIECE_LAYER_HINT = "layerHint";
+ protected static final String STRUCTURE_PIECE_TOP_HINT = "topHint";
+
+ protected final List<List<GT_MetaTileEntity_Hatch_Output>> mOutputHatchesByLayer = new ArrayList<>();
+ protected int mHeight;
+ protected int mCasing;
+ protected boolean mTopLayerFound;
+
+ private static IStructureDefinition<GregtechMetaTileEntity_Adv_DistillationTower> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_Adv_DistillationTower(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_Adv_DistillationTower(String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_Adv_DistillationTower(this.mName);
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_Adv_DistillationTower> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ IHatchElement<GregtechMetaTileEntity_Adv_DistillationTower> layeredOutputHatch = OutputHatch
+ .withCount(GregtechMetaTileEntity_Adv_DistillationTower::getCurrentLayerOutputHatchCount)
+ .withAdder(GregtechMetaTileEntity_Adv_DistillationTower::addLayerOutputHatch);
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_Adv_DistillationTower>builder()
+ .addShape(STRUCTURE_PIECE_BASE, transpose(new String[][] { { "b~b", "bbb", "bbb" }, }))
+ .addShape(STRUCTURE_PIECE_LAYER, transpose(new String[][] { { "lll", "lcl", "lll" }, }))
+ .addShape(STRUCTURE_PIECE_LAYER_HINT, transpose(new String[][] { { "lll", "l-l", "lll" }, }))
+ .addShape(STRUCTURE_PIECE_TOP_HINT, transpose(new String[][] { { "ttt", "ttt", "ttt" }, }))
+ .addElement(
+ 'b',
+ ofChain(
+ buildHatchAdder(GregtechMetaTileEntity_Adv_DistillationTower.class)
+ .atLeast(Energy, OutputBus, InputHatch, InputBus, Maintenance)
+ .disallowOnly(ForgeDirection.UP)
+ .casingIndex(getCasingTextureId())
+ .dot(1)
+ .build(),
+ ofBlock(GregTech_API.sBlockCasings4, 1)))
+ .addElement(
+ 'l',
+ ofChain(
+ buildHatchAdder(GregtechMetaTileEntity_Adv_DistillationTower.class)
+ .atLeast(layeredOutputHatch, Energy, Maintenance)
+ .disallowOnly(ForgeDirection.UP, ForgeDirection.DOWN)
+ .casingIndex(getCasingTextureId())
+ .dot(2)
+ .build(),
+ ofHatchAdder(
+ GregtechMetaTileEntity_Adv_DistillationTower::addMufflerToMachineList,
+ getCasingTextureId(),
+ 3),
+ ofBlock(GregTech_API.sBlockCasings4, 1)))
+ .addElement(
+ 'c',
+ ofChain(
+ onElementPass(
+ GregtechMetaTileEntity_Adv_DistillationTower::onTopLayerFound,
+ ofHatchAdder(
+ GregtechMetaTileEntity_Adv_DistillationTower::addMufflerToMachineList,
+ getCasingTextureId(),
+ 3)),
+ onElementPass(
+ GregtechMetaTileEntity_Adv_DistillationTower::onTopLayerFound,
+ ofHatchAdder(
+ GregtechMetaTileEntity_Adv_DistillationTower::addOutputToMachineList,
+ getCasingTextureId(),
+ 3)),
+ onElementPass(
+ GregtechMetaTileEntity_Adv_DistillationTower::onTopLayerFound,
+ ofHatchAdder(
+ GregtechMetaTileEntity_Adv_DistillationTower::addMaintenanceToMachineList,
+ getCasingTextureId(),
+ 3)),
+ onElementPass(
+ GregtechMetaTileEntity_Adv_DistillationTower::onTopLayerFound,
+ ofBlock(GregTech_API.sBlockCasings4, 1)),
+ isAir()))
+ .addElement(
+ 't',
+ buildHatchAdder(GregtechMetaTileEntity_Adv_DistillationTower.class)
+ .atLeast(layeredOutputHatch, Muffler)
+ .disallowOnly(ForgeDirection.DOWN)
+ .casingIndex(getCasingTextureId())
+ .dot(2)
+ .buildAndChain(GregTech_API.sBlockCasings4, 1))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ protected int getCurrentLayerOutputHatchCount() {
+ return mOutputHatchesByLayer.size() < mHeight || mHeight <= 0 ? 0
+ : mOutputHatchesByLayer.get(mHeight - 1)
+ .size();
+ }
+
+ protected boolean addLayerOutputHatch(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) {
+ if (aTileEntity == null || aTileEntity.isDead()
+ || !(aTileEntity.getMetaTileEntity() instanceof GT_MetaTileEntity_Hatch_Output tHatch)) return false;
+ while (mOutputHatchesByLayer.size() < mHeight) mOutputHatchesByLayer.add(new ArrayList<>());
+ tHatch.updateTexture(aBaseCasingIndex);
+ return mOutputHatchesByLayer.get(mHeight - 1)
+ .add(tHatch) && mOutputHatches.add(tHatch);
+ }
+
+ protected void onTopLayerFound() {
+ mTopLayerFound = true;
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Advanced Distillation Tower")
+ .addInfo("Use 85% less energy in distillery mode")
+ .addInfo("250%/100% faster in DT/distillery mode")
+ .addInfo("Right click the controller with screwdriver to change mode.")
+ .addInfo("Max parallel dictated by tower tier and mode")
+ .addInfo("DTower Mode: T1=4, T2=12")
+ .addInfo("Distilery Mode: Tower Tier * (4*InputTier)")
+ .addInfo("Distilery Mode require a full height tower")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .addCasingInfoMin("Clean Stainless Steel Machine Casing", 7, false)
+ .addInputBus("Bottom Casing", 1)
+ .addOutputBus("Bottom Casing", 1)
+ .addInputHatch("Bottom Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addOutputHatch("One per layer except bottom", 2)
+ .addMufflerHatch("Top Casing", 3)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(STRUCTURE_PIECE_BASE, stackSize, hintsOnly, 1, 0, 0);
+ int tTotalHeight = Math.min(12, stackSize.stackSize + 2); // min 2 output layer, so at least 1 + 2 height
+ for (int i = 1; i < tTotalHeight - 1; i++) {
+ buildPiece(STRUCTURE_PIECE_LAYER_HINT, stackSize, hintsOnly, 1, i, 0);
+ }
+ buildPiece(STRUCTURE_PIECE_TOP_HINT, stackSize, hintsOnly, 1, tTotalHeight - 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ mHeight = 0;
+ int built = survivialBuildPiece(STRUCTURE_PIECE_BASE, stackSize, 1, 0, 0, elementBudget, env, false, true);
+ if (built >= 0) return built;
+ int tTotalHeight = Math.min(12, stackSize.stackSize + 2); // min 2 output layer, so at least 1 + 2 height
+ for (int i = 1; i < tTotalHeight - 1; i++) {
+ mHeight = i;
+ built = survivialBuildPiece(
+ STRUCTURE_PIECE_LAYER_HINT,
+ stackSize,
+ 1,
+ i,
+ 0,
+ elementBudget,
+ env,
+ false,
+ true);
+ if (built >= 0) return built;
+ }
+ mHeight = tTotalHeight - 1;
+ return survivialBuildPiece(
+ STRUCTURE_PIECE_TOP_HINT,
+ stackSize,
+ 1,
+ tTotalHeight - 1,
+ 0,
+ elementBudget,
+ env,
+ false,
+ true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ // reset
+ mOutputHatchesByLayer.forEach(List::clear);
+ mHeight = 1;
+ mTopLayerFound = false;
+
+ // check base
+ if (!checkPiece(STRUCTURE_PIECE_BASE, 1, 0, 0)) return false;
+
+ // check each layer
+ while (mHeight < 12) {
+ if (!checkPiece(STRUCTURE_PIECE_LAYER, 1, mHeight, 0)) {
+ return false;
+ }
+ if (mOutputHatchesByLayer.size() < mHeight || mOutputHatchesByLayer.get(mHeight - 1)
+ .isEmpty())
+ // layer without output hatch
+ return false;
+ if (mTopLayerFound || !mMufflerHatches.isEmpty()) {
+ break;
+ }
+ // not top
+ mHeight++;
+ }
+ boolean check = mTopLayerFound && mHeight >= 2 && checkHatch();
+ if (check && mHeight < 11) {
+ // force the mode to DT if not in full height
+ mMode = Mode.DistillationTower;
+ mLastRecipe = null;
+ }
+ return check;
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return mMode.getRecipeMap();
+ }
+
+ @Nonnull
+ @Override
+ public Collection<RecipeMap<?>> getAvailableRecipeMaps() {
+ return Arrays.asList(RecipeMaps.distilleryRecipes, RecipeMaps.distillationTowerRecipes);
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ protected IAlignmentLimits getInitialAlignmentLimits() {
+ // don't rotate a freaking tower, it won't work
+ return (d, r, f) -> d.offsetY == 0 && r.isNotRotated() && !f.isVerticallyFliped();
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(ItemStack aStack) {
+ if (this.mMode == Mode.Distillery)
+ return CORE.ConfigSwitches.pollutionPerSecondMultiAdvDistillationTower_ModeDistillery;
+ return CORE.ConfigSwitches.pollutionPerSecondMultiAdvDistillationTower_ModeDT;
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ aNBT.setByte("mMode", (byte) mMode.ordinal());
+ aNBT.setBoolean("mUpgraded", mUpgraded);
+ super.saveNBTData(aNBT);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ mMode = Mode.values()[aNBT.getByte("mMode")];
+ mUpgraded = aNBT.getBoolean("mUpgraded");
+ super.loadNBTData(aNBT);
+ }
+
+ @Override
+ public void onModeChangeByScrewdriver(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+ if (mHeight < 11) {
+ PlayerUtils.messagePlayer(aPlayer, "Cannot switch mode if not in full height.");
+ return;
+ }
+ mMode = mMode.next();
+ PlayerUtils.messagePlayer(aPlayer, "Now running in " + mMode + " Mode.");
+ mLastRecipe = null;
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public boolean addOutput(FluidStack aLiquid) {
+ if (aLiquid == null) return false;
+ FluidStack copiedFluidStack = aLiquid.copy();
+ for (List<GT_MetaTileEntity_Hatch_Output> hatches : mOutputHatchesByLayer) {
+ if (dumpFluid(hatches, copiedFluidStack, true)) return true;
+ }
+ for (List<GT_MetaTileEntity_Hatch_Output> hatches : mOutputHatchesByLayer) {
+ if (dumpFluid(hatches, copiedFluidStack, false)) return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected void addFluidOutputs(FluidStack[] mOutputFluids2) {
+ if (mMode == Mode.DistillationTower) {
+ // dt mode
+ for (int i = 0; i < mOutputFluids2.length && i < mOutputHatchesByLayer.size(); i++) {
+ FluidStack tStack = mOutputFluids2[i].copy();
+ if (!dumpFluid(mOutputHatchesByLayer.get(i), tStack, true))
+ dumpFluid(mOutputHatchesByLayer.get(i), tStack, false);
+ }
+ } else {
+ // distillery mode
+ for (FluidStack outputFluidStack : mOutputFluids2) {
+ addOutput(outputFluidStack);
+ }
+ }
+ }
+
+ @Override
+ public List<? extends IFluidStore> getFluidOutputSlots(FluidStack[] toOutput) {
+ return getFluidOutputSlotsByLayer(toOutput, mOutputHatchesByLayer);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Distillery, Distillation Tower";
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic().setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ protected void setupProcessingLogic(ProcessingLogic logic) {
+ super.setupProcessingLogic(logic);
+ logic.setEuModifier(mMode == Mode.Distillery ? 0.15F : 1F);
+ logic.setSpeedBonus(mMode == Mode.Distillery ? 1F / 2F : 1F / 3.5F);
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return switch (mMode) {
+ case DistillationTower -> getTierOfTower() == 1 ? 4 : getTierOfTower() == 2 ? 12 : 0;
+ case Distillery -> getTierOfTower() * (4 * GT_Utility.getTier(this.getMaxInputVoltage()));
+ default -> 0;
+ };
+ }
+
+ private int getTierOfTower() {
+ return mUpgraded ? 2 : 1;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return Textures.BlockIcons.OVERLAY_FRONT_DISTILLATION_TOWER_ACTIVE;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return Textures.BlockIcons.OVERLAY_FRONT_DISTILLATION_TOWER;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return 49;
+ }
+
+ @Override
+ public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {
+ super.onPostTick(aBaseMetaTileEntity, aTick);
+ if (aTick % 20 == 0 && !mUpgraded) {
+ ItemStack aGuiStack = this.getControllerSlot();
+ if (aGuiStack != null) {
+ if (GT_Utility.areStacksEqual(aGuiStack, GregtechItemList.Distillus_Upgrade_Chip.get(1))) {
+ this.mUpgraded = true;
+ mInventory[1] = ItemUtils.depleteStack(aGuiStack);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean canDumpFluidToME() {
+ // All fluids can be dumped to ME only if each layer contains a ME Output Hatch.
+ return this.mOutputHatchesByLayer.stream()
+ .allMatch(
+ tLayerOutputHatches -> tLayerOutputHatches.stream()
+ .anyMatch(tHatch -> tHatch instanceof GT_MetaTileEntity_Hatch_Output_ME));
+ }
+
+ @Override
+ public void setItemNBT(NBTTagCompound aNBT) {
+ aNBT.setBoolean("mUpgraded", mUpgraded);
+ super.setItemNBT(aNBT);
+ }
+
+ @Override
+ public void addAdditionalTooltipInformation(ItemStack stack, List<String> tooltip) {
+ super.addAdditionalTooltipInformation(stack, tooltip);
+ NBTTagCompound aNBT = stack.getTagCompound();
+ if (aNBT != null && aNBT.hasKey("mUpgraded")) {
+ tooltip.add(StatCollector.translateToLocal("tooltip.large_distill_tower.upgraded"));
+ }
+ }
+
+ private enum Mode {
+
+ DistillationTower(RecipeMaps.distillationTowerRecipes),
+ Distillery(RecipeMaps.distilleryRecipes),;
+
+ static final Mode[] VALUES = values();
+ private final RecipeMap<?> recipeMap;
+
+ Mode(RecipeMap<?> recipeMap) {
+ this.recipeMap = recipeMap;
+ }
+
+ public RecipeMap<?> getRecipeMap() {
+ return recipeMap;
+ }
+
+ public Mode next() {
+ return VALUES[(ordinal() + 1) % VALUES.length];
+ }
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_EBF.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_EBF.java
new file mode 100644
index 0000000000..89c219c14e
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_EBF.java
@@ -0,0 +1,333 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing.advanced;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+import static gregtech.api.util.GT_StructureUtility.ofCoil;
+import static gregtech.api.util.GT_Utility.filterValidMTEs;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.ChatComponentTranslation;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.StatCollector;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.HeatingCoilLevel;
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_OverclockCalculator;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.GT_Utility;
+import gregtech.api.util.shutdown.ShutDownReasonRegistry;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.minecraft.FluidUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GT_MetaTileEntity_Hatch_CustomFluidBase;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_Adv_EBF extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_Adv_EBF>
+ implements ISurvivalConstructable {
+
+ public static int CASING_TEXTURE_ID;
+ public static String mHotFuelName = "Blazing Pyrotheum";
+ public static String mCasingName = "Volcanus Casing";
+ public static String mHatchName = "Pyrotheum Hatch";
+ private static IStructureDefinition<GregtechMetaTileEntity_Adv_EBF> STRUCTURE_DEFINITION = null;
+ private int mCasing;
+ private final ArrayList<GT_MetaTileEntity_Hatch_CustomFluidBase> mPyrotheumHatches = new ArrayList<>();
+
+ private HeatingCoilLevel mHeatingCapacity = HeatingCoilLevel.None;
+
+ public GregtechMetaTileEntity_Adv_EBF(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ CASING_TEXTURE_ID = TAE.getIndexFromPage(2, 11);
+ }
+
+ public GregtechMetaTileEntity_Adv_EBF(String aName) {
+ super(aName);
+ CASING_TEXTURE_ID = TAE.getIndexFromPage(2, 11);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Blast Furnace";
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_Adv_EBF(this.mName);
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Factory Grade Advanced Blast Furnace")
+ .addInfo("Speed: +120% | EU Usage: 90% | Parallel: 8")
+ .addInfo("Consumes 10L of " + mHotFuelName + " per second during operation")
+ .addInfo("Constructed exactly the same as a normal EBF")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .addController("Bottom center")
+ .addCasingInfoMin(mCasingName, 8, false)
+ .addInputHatch("Any Casing", 1)
+ .addInputBus("Any Casing", 1)
+ .addOutputBus("Any Casing", 1)
+ .addOutputHatch("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addOtherStructurePart(mHatchName, "Any Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public String[] getExtraInfoData() {
+ return new String[] { StatCollector.translateToLocal("GT5U.EBF.heat") + ": "
+ + EnumChatFormatting.GREEN
+ + GT_Utility.formatNumbers(mHeatingCapacity.getHeat())
+ + EnumChatFormatting.RESET
+ + " K" };
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_Adv_EBF> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_Adv_EBF>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC" }, { "HHH", "H-H", "HHH" }, { "HHH", "H-H", "HHH" },
+ { "C~C", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ ofChain(
+ buildHatchAdder(GregtechMetaTileEntity_Adv_EBF.class)
+ .adder(GregtechMetaTileEntity_Adv_EBF::addPyrotheumHatch)
+ .hatchId(968)
+ .shouldReject(x -> !x.mPyrotheumHatches.isEmpty())
+ .casingIndex(CASING_TEXTURE_ID)
+ .dot(1)
+ .build(),
+ buildHatchAdder(GregtechMetaTileEntity_Adv_EBF.class)
+ .atLeast(InputBus, OutputBus, Maintenance, Energy, Muffler, InputHatch, OutputHatch)
+ .casingIndex(CASING_TEXTURE_ID)
+ .dot(1)
+ .build(),
+ onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings3Misc, 11))))
+ .addElement(
+ 'H',
+ ofCoil(GregtechMetaTileEntity_Adv_EBF::setCoilLevel, GregtechMetaTileEntity_Adv_EBF::getCoilLevel))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 3, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 3, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ mPyrotheumHatches.clear();
+ setCoilLevel(HeatingCoilLevel.None);
+ return checkPiece(mName, 1, 3, 0) && mCasing >= 8 && getCoilLevel() != HeatingCoilLevel.None && checkHatch();
+ }
+
+ @Override
+ public boolean checkHatch() {
+ return super.checkHatch() && !mPyrotheumHatches.isEmpty();
+ }
+
+ private boolean addPyrotheumHatch(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) {
+ if (aTileEntity == null) {
+ return false;
+ } else {
+ IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+ if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_CustomFluidBase
+ && aMetaTileEntity.getBaseMetaTileEntity()
+ .getMetaTileID() == 968) {
+ return addToMachineListInternal(mPyrotheumHatches, aTileEntity, aBaseCasingIndex);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void updateSlots() {
+ for (GT_MetaTileEntity_Hatch_CustomFluidBase tHatch : filterValidMTEs(mPyrotheumHatches)) tHatch.updateSlots();
+ super.updateSlots();
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return CASING_TEXTURE_ID;
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return RecipeMaps.blastFurnaceRecipes;
+ }
+
+ @Override
+ public int getRecipeCatalystPriority() {
+ return -1;
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic() {
+
+ @NotNull
+ @Override
+ protected CheckRecipeResult validateRecipe(@NotNull GT_Recipe recipe) {
+ return recipe.mSpecialValue <= getCoilLevel().getHeat() ? CheckRecipeResultRegistry.SUCCESSFUL
+ : CheckRecipeResultRegistry.insufficientHeat(recipe.mSpecialValue);
+ }
+
+ @NotNull
+ @Override
+ protected GT_OverclockCalculator createOverclockCalculator(@NotNull GT_Recipe recipe) {
+ return super.createOverclockCalculator(recipe).setHeatOC(true)
+ .setHeatDiscount(true)
+ .setRecipeHeat(recipe.mSpecialValue)
+ .setMachineHeat((int) getCoilLevel().getHeat());
+ }
+ }.setSpeedBonus(1F / 2.2F)
+ .setEuModifier(0.9F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiAdvEBF;
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(ItemStack aStack) {
+ return false;
+ }
+
+ private int mGraceTimer = 2;
+
+ @Override
+ public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {
+ super.onPostTick(aBaseMetaTileEntity, aTick);
+ // Try dry Pyrotheum after all other logic
+ if (this.mStartUpCheck < 0) {
+ if (this.mMaxProgresstime > 0 && this.mProgresstime != 0 || this.getBaseMetaTileEntity()
+ .hasWorkJustBeenEnabled()) {
+ if (aTick % 10 == 0 || this.getBaseMetaTileEntity()
+ .hasWorkJustBeenEnabled()) {
+ if (!this.depleteInputFromRestrictedHatches(this.mPyrotheumHatches, 5)) {
+ if (mGraceTimer-- == 0) {
+ this.causeMaintenanceIssue();
+ this.stopMachine(
+ ShutDownReasonRegistry
+ .outOfFluid(Objects.requireNonNull(FluidUtils.getFluidStack("pyrotheum", 10))));
+ mGraceTimer = 2;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 8;
+ }
+
+ @Override
+ public void onModeChangeByScrewdriver(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+ inputSeparation = !inputSeparation;
+ aPlayer.addChatMessage(
+ new ChatComponentTranslation(
+ inputSeparation ? "interaction.separateBusses.enabled" : "interaction.separateBusses.disabled"));
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ if (!aNBT.hasKey(INPUT_SEPARATION_NBT_KEY)) {
+ inputSeparation = aNBT.getBoolean("isBussesSeparate");
+ }
+ }
+
+ public HeatingCoilLevel getCoilLevel() {
+ return mHeatingCapacity;
+ }
+
+ public void setCoilLevel(HeatingCoilLevel aCoilLevel) {
+ mHeatingCapacity = aCoilLevel;
+ }
+
+ @Override
+ public boolean supportsInputSeparation() {
+ return true;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_Fusion_MK4.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_Fusion_MK4.java
new file mode 100644
index 0000000000..0981a34b85
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_Fusion_MK4.java
@@ -0,0 +1,200 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing.advanced;
+
+import java.lang.reflect.Method;
+
+import net.minecraft.block.Block;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import gregtech.api.enums.Dyes;
+import gregtech.api.enums.TAE;
+import gregtech.api.enums.Textures;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.metatileentity.MetaTileEntity;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Energy;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output;
+import gregtech.api.objects.GT_RenderedTexture;
+import gregtech.api.objects.overclockdescriber.OverclockDescriber;
+import gregtech.api.render.TextureFactory;
+import gregtech.api.util.AdvancedFusionOverclockDescriber;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.common.tileentities.machines.multi.GT_MetaTileEntity_FusionComputer;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.reflect.ReflectionUtils;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_Adv_Fusion_MK4 extends GT_MetaTileEntity_FusionComputer {
+
+ public static final Method mUpdateHatchTexture;
+
+ static {
+ mUpdateHatchTexture = ReflectionUtils.getMethod(GT_MetaTileEntity_Hatch.class, "updateTexture", int.class);
+ }
+
+ public GregtechMetaTileEntity_Adv_Fusion_MK4(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_Adv_Fusion_MK4(String aName) {
+ super(aName);
+ }
+
+ @Override
+ protected OverclockDescriber createOverclockDescriber() {
+ return new AdvancedFusionOverclockDescriber((byte) tier(), capableStartupCanonical());
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType("Fusion Reactor")
+ .addInfo("HARNESSING THE POWER OF A BLUE GIANT")
+ .addInfo("Controller block for the Fusion Reactor Mk IV")
+ .addInfo("131072EU/t and 320M EU capacity per Energy Hatch")
+ .addInfo("If the recipe has a startup cost greater than the")
+ .addInfo("number of energy hatches * cap, you can't do it")
+ .addInfo("Performs 4/4 overclocks")
+ .addSeparator()
+ .beginStructureBlock(15, 3, 15, false)
+ .addController("See diagram when placed")
+ .addCasingInfoMin("Fusion Machine Casings MK III", 79, false)
+ .addStructureInfo("Cover the coils with casing")
+ .addOtherStructurePart("Advanced Fusion Coils", "Center part of the ring")
+ .addEnergyHatch("1-16, Specified casings", 2)
+ .addInputHatch("2-16, Specified casings", 1)
+ .addOutputHatch("1-16, Specified casings", 3)
+ .addStructureInfo("ALL Hatches must be UHV or better")
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public int tier() {
+ return 9;
+ }
+
+ @Override
+ public long maxEUStore() {
+ return (640010000L * 4) * (Math.min(16, this.mEnergyHatches.size())) / 8L;
+ }
+
+ @Override
+ public long capableStartupCanonical() {
+ return 5_120_000_000L;
+ }
+
+ @Override
+ public int getRecipeCatalystPriority() {
+ return -1;
+ }
+
+ @Override
+ public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_Adv_Fusion_MK4(mName);
+ }
+
+ @Override
+ public Block getCasing() {
+ return getFusionCoil();
+ }
+
+ @Override
+ public int getCasingMeta() {
+ return 12;
+ }
+
+ @Override
+ public Block getFusionCoil() {
+ return ModBlocks.blockCasings3Misc;
+ }
+
+ @Override
+ public int getFusionCoilMeta() {
+ return 13;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return super.createProcessingLogic().setOverclock(2, 2);
+ }
+
+ @Override
+ public ITexture[] getTexture(final IGregTechTileEntity aBaseMetaTileEntity, final ForgeDirection side,
+ final ForgeDirection facing, final int aColorIndex, final boolean aActive, final boolean aRedstone) {
+ if (side == facing) {
+ return new ITexture[] {
+ new GT_RenderedTexture(
+ Textures.BlockIcons.MACHINE_CASING_FUSION_GLASS,
+ Dyes.getModulation(-1, Dyes._NULL.mRGBa)),
+ TextureFactory.builder()
+ .addIcon(this.getIconOverlay())
+ .extFacing()
+ .build() };
+ } else if (!aActive) {
+ return new ITexture[] { new GT_RenderedTexture(
+ Textures.BlockIcons.MACHINE_CASING_FUSION_GLASS,
+ Dyes.getModulation(-1, Dyes._NULL.mRGBa)) };
+ } else {
+ return new ITexture[] { new GT_RenderedTexture(
+ TexturesGtBlock.TEXTURE_CASING_FUSION_CASING_ULTRA,
+ Dyes.getModulation(-1, Dyes._NULL.mRGBa)) };
+ }
+ }
+
+ @Override
+ public ITexture getTextureOverlay() {
+ return new GT_RenderedTexture(
+ this.getBaseMetaTileEntity()
+ .isActive() ? TexturesGtBlock.Casing_Machine_Screen_3 : TexturesGtBlock.Casing_Machine_Screen_1);
+ }
+
+ public IIconContainer getIconOverlay() {
+ return this.getBaseMetaTileEntity()
+ .isActive() ? TexturesGtBlock.Casing_Machine_Screen_3 : TexturesGtBlock.Casing_Machine_Screen_1;
+ }
+
+ @Override
+ public boolean turnCasingActive(final boolean status) {
+ try {
+ if (this.mEnergyHatches != null) {
+ for (final GT_MetaTileEntity_Hatch_Energy hatch : this.mEnergyHatches) {
+ mUpdateHatchTexture.invoke(hatch, (status ? TAE.getIndexFromPage(2, 14) : 53));
+ }
+ }
+ if (this.mOutputHatches != null) {
+ for (final GT_MetaTileEntity_Hatch_Output hatch2 : this.mOutputHatches) {
+ mUpdateHatchTexture.invoke(hatch2, (status ? TAE.getIndexFromPage(2, 14) : 53));
+ }
+ }
+ if (this.mInputHatches != null) {
+ for (final GT_MetaTileEntity_Hatch_Input hatch3 : this.mInputHatches) {
+ mUpdateHatchTexture.invoke(hatch3, (status ? TAE.getIndexFromPage(2, 14) : 53));
+ }
+ }
+ } catch (Throwable t) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String[] getInfoData() {
+ String tier = "IV";
+ float plasmaOut = 0;
+ int powerRequired = 0;
+ if (this.mLastRecipe != null) {
+ powerRequired = this.mLastRecipe.mEUt;
+ if (this.mLastRecipe.getFluidOutput(0) != null) {
+ plasmaOut = (float) this.mLastRecipe.getFluidOutput(0).amount / (float) this.mLastRecipe.mDuration;
+ }
+ }
+
+ return new String[] { "Fusion Reactor MK " + tier, "EU Required: " + powerRequired + "EU/t",
+ "Stored EU: " + mEUStore + " / " + maxEUStore(), "Plasma Output: " + plasmaOut + "L/t" };
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_Fusion_MK5.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_Fusion_MK5.java
new file mode 100644
index 0000000000..b2c2e5eb27
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_Fusion_MK5.java
@@ -0,0 +1,200 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing.advanced;
+
+import java.lang.reflect.Method;
+
+import net.minecraft.block.Block;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import gregtech.api.enums.Dyes;
+import gregtech.api.enums.TAE;
+import gregtech.api.enums.Textures;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.metatileentity.MetaTileEntity;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Energy;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output;
+import gregtech.api.objects.GT_RenderedTexture;
+import gregtech.api.objects.overclockdescriber.OverclockDescriber;
+import gregtech.api.render.TextureFactory;
+import gregtech.api.util.AdvancedFusionOverclockDescriber;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.common.tileentities.machines.multi.GT_MetaTileEntity_FusionComputer;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.reflect.ReflectionUtils;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_Adv_Fusion_MK5 extends GT_MetaTileEntity_FusionComputer {
+
+ public static final Method mUpdateHatchTexture;
+
+ static {
+ mUpdateHatchTexture = ReflectionUtils.getMethod(GT_MetaTileEntity_Hatch.class, "updateTexture", int.class);
+ }
+
+ public GregtechMetaTileEntity_Adv_Fusion_MK5(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_Adv_Fusion_MK5(String aName) {
+ super(aName);
+ }
+
+ @Override
+ protected OverclockDescriber createOverclockDescriber() {
+ return new AdvancedFusionOverclockDescriber((byte) tier(), capableStartupCanonical());
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType("Fusion Reactor")
+ .addInfo("HARNESSING THE POWER OF A NEUTRON STAR")
+ .addInfo("Controller block for the Fusion Reactor Mk V")
+ .addInfo("524,288EU/t and 1.28B EU capacity per Energy Hatch")
+ .addInfo("If the recipe has a startup cost greater than the")
+ .addInfo("number of energy hatches * cap, you can't do it")
+ .addInfo("Performs 4/4 overclocks")
+ .addSeparator()
+ .beginStructureBlock(15, 3, 15, false)
+ .addController("See diagram when placed")
+ .addCasingInfoMin("Fusion Machine Casings MK IV", 79, false)
+ .addStructureInfo("Cover the coils with casing")
+ .addOtherStructurePart("Advanced Fusion Coils II", "Center part of the ring")
+ .addEnergyHatch("1-16, Specified casings", 2)
+ .addInputHatch("2-16, Specified casings", 1)
+ .addOutputHatch("1-16, Specified casings", 3)
+ .addStructureInfo("ALL Hatches must be UEV or better")
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public int tier() {
+ return 10;
+ }
+
+ @Override
+ public long maxEUStore() {
+ return (640010000L * 16) * (Math.min(16, this.mEnergyHatches.size())) / 8L;
+ }
+
+ @Override
+ public long capableStartupCanonical() {
+ return 20_480_000_000L;
+ }
+
+ @Override
+ public int getRecipeCatalystPriority() {
+ return -1;
+ }
+
+ @Override
+ public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_Adv_Fusion_MK5(mName);
+ }
+
+ @Override
+ public Block getCasing() {
+ return getFusionCoil();
+ }
+
+ @Override
+ public int getCasingMeta() {
+ return 0;
+ }
+
+ @Override
+ public Block getFusionCoil() {
+ return ModBlocks.blockCasings6Misc;
+ }
+
+ @Override
+ public int getFusionCoilMeta() {
+ return 1;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return super.createProcessingLogic().setOverclock(2, 2);
+ }
+
+ @Override
+ public ITexture[] getTexture(final IGregTechTileEntity aBaseMetaTileEntity, final ForgeDirection side,
+ final ForgeDirection facing, final int aColorIndex, final boolean aActive, final boolean aRedstone) {
+ if (side == facing) {
+ return new ITexture[] {
+ new GT_RenderedTexture(
+ Textures.BlockIcons.MACHINE_CASING_FUSION_GLASS,
+ Dyes.getModulation(-1, Dyes._NULL.mRGBa)),
+ TextureFactory.builder()
+ .addIcon(this.getIconOverlay())
+ .extFacing()
+ .build() };
+ } else if (!aActive) {
+ return new ITexture[] { new GT_RenderedTexture(
+ Textures.BlockIcons.MACHINE_CASING_FUSION_GLASS,
+ Dyes.getModulation(-1, Dyes._NULL.mRGBa)) };
+ } else {
+ return new ITexture[] { new GT_RenderedTexture(
+ TexturesGtBlock.TEXTURE_CASING_FUSION_CASING_HYPER,
+ Dyes.getModulation(-1, Dyes._NULL.mRGBa)) };
+ }
+ }
+
+ @Override
+ public ITexture getTextureOverlay() {
+ return new GT_RenderedTexture(
+ this.getBaseMetaTileEntity()
+ .isActive() ? TexturesGtBlock.Casing_Machine_Screen_Rainbow : TexturesGtBlock.Casing_Machine_Screen_1);
+ }
+
+ public IIconContainer getIconOverlay() {
+ return this.getBaseMetaTileEntity()
+ .isActive() ? TexturesGtBlock.Casing_Machine_Screen_Rainbow : TexturesGtBlock.Casing_Machine_Screen_1;
+ }
+
+ @Override
+ public boolean turnCasingActive(final boolean status) {
+ try {
+ if (this.mEnergyHatches != null) {
+ for (final GT_MetaTileEntity_Hatch_Energy hatch : this.mEnergyHatches) {
+ mUpdateHatchTexture.invoke(hatch, (status ? TAE.getIndexFromPage(3, 6) : 53));
+ }
+ }
+ if (this.mOutputHatches != null) {
+ for (final GT_MetaTileEntity_Hatch_Output hatch2 : this.mOutputHatches) {
+ mUpdateHatchTexture.invoke(hatch2, (status ? TAE.getIndexFromPage(3, 6) : 53));
+ }
+ }
+ if (this.mInputHatches != null) {
+ for (final GT_MetaTileEntity_Hatch_Input hatch3 : this.mInputHatches) {
+ mUpdateHatchTexture.invoke(hatch3, (status ? TAE.getIndexFromPage(3, 6) : 53));
+ }
+ }
+ } catch (Throwable t) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String[] getInfoData() {
+ String tier = "V";
+ float plasmaOut = 0;
+ int powerRequired = 0;
+ if (this.mLastRecipe != null) {
+ powerRequired = this.mLastRecipe.mEUt;
+ if (this.mLastRecipe.getFluidOutput(0) != null) {
+ plasmaOut = (float) this.mLastRecipe.getFluidOutput(0).amount / (float) this.mLastRecipe.mDuration;
+ }
+ }
+
+ return new String[] { "Fusion Reactor MK " + tier, "EU Required: " + powerRequired + "EU/t",
+ "Stored EU: " + mEUStore + " / " + maxEUStore(), "Plasma Output: " + plasmaOut + "L/t" };
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_HeatExchanger.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_HeatExchanger.java
new file mode 100644
index 0000000000..e4340c4d28
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_HeatExchanger.java
@@ -0,0 +1,414 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing.advanced;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.util.GT_StructureUtility.ofHatchAdder;
+
+import net.minecraft.block.Block;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.StatCollector;
+import net.minecraftforge.fluids.FluidRegistry;
+import net.minecraftforge.fluids.FluidStack;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.GregTech_API;
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.util.GT_Log;
+import gregtech.api.util.GT_ModHandler;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.block.base.BasicBlock.BlockTypes;
+import gtPlusPlus.core.block.base.BlockBaseModular;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.material.ALLOY;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_Adv_HeatExchanger
+ extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_Adv_HeatExchanger> {
+
+ private static final int CASING_INDEX = TAE.getIndexFromPage(1, 12);
+ private static final String STRUCTURE_PIECE_MAIN = "main";
+
+ private static final IStructureDefinition<GregtechMetaTileEntity_Adv_HeatExchanger> STRUCTURE_DEFINITION = StructureDefinition
+ .<GregtechMetaTileEntity_Adv_HeatExchanger>builder()
+ .addShape(
+ STRUCTURE_PIECE_MAIN,
+ transpose(
+ new String[][] { { " ccc ", "cCCCc", "cCCCc", "cCCCc", " ccc " },
+ { " ccc ", "cPPPc", "cPPPc", "cPPPc", " ccc " }, { " ccc ", "cPPPc", "cPPPc", "cPPPc", " ccc " },
+ { " ccc ", "cPPPc", "cPPPc", "cPPPc", " ccc " }, { " ccc ", "cPPPc", "cPPPc", "cPPPc", " ccc " },
+ { " c~c ", "cPPPc", "cPPPc", "cPPPc", " ccc " }, { " hhh ", "hHHHh", "hHHHh", "hHHHh", " hhh " },
+ { " f f ", "f f", " ", "f f", " f f " },
+ { " f f ", "f f", " ", "f f", " f f " }, }))
+ .addElement('P', ofBlock(GregTech_API.sBlockCasings2, 15))
+ .addElement('f', ofBlock(getFrame(), 0))
+ .addElement(
+ 'C',
+ ofChain(
+ ofHatchAdder(
+ GregtechMetaTileEntity_Adv_HeatExchanger::addColdFluidOutputToMachineList,
+ CASING_INDEX,
+ 2),
+ onElementPass(
+ GregtechMetaTileEntity_Adv_HeatExchanger::onCasingAdded,
+ ofBlock(ModBlocks.blockSpecialMultiCasings, 14))))
+ .addElement(
+ 'H',
+ ofChain(
+ ofHatchAdder(GregtechMetaTileEntity_Adv_HeatExchanger::addHotFluidInputToMachineList, CASING_INDEX, 3),
+ onElementPass(
+ GregtechMetaTileEntity_Adv_HeatExchanger::onCasingAdded,
+ ofBlock(ModBlocks.blockSpecialMultiCasings, 14))))
+ .addElement(
+ 'h',
+ ofChain(
+ ofHatchAdder(GregtechMetaTileEntity_Adv_HeatExchanger::addInputToMachineList, CASING_INDEX, 1),
+ ofHatchAdder(GregtechMetaTileEntity_Adv_HeatExchanger::addOutputToMachineList, CASING_INDEX, 1),
+ ofHatchAdder(GregtechMetaTileEntity_Adv_HeatExchanger::addMaintenanceToMachineList, CASING_INDEX, 1),
+ onElementPass(
+ GregtechMetaTileEntity_Adv_HeatExchanger::onCasingAdded,
+ ofBlock(ModBlocks.blockSpecialMultiCasings, 14))))
+ .addElement(
+ 'c',
+ ofChain(
+ onElementPass(
+ GregtechMetaTileEntity_Adv_HeatExchanger::onCasingAdded,
+ ofBlock(ModBlocks.blockSpecialMultiCasings, 14))))
+ .build();
+ public static float penalty_per_config = 0.015f; // penalize 1.5% efficiency per circuitry level (1-25)
+
+ private GT_MetaTileEntity_Hatch_Input mInputHotFluidHatch;
+ private GT_MetaTileEntity_Hatch_Output mOutputColdFluidHatch;
+ private boolean superheated = false;
+ private int superheated_threshold = 0;
+ private float water;
+ private int mCasingAmount;
+
+ public GregtechMetaTileEntity_Adv_HeatExchanger(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_Adv_HeatExchanger(String aName) {
+ super(aName);
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the XL Heat Exchanger")
+ .addInfo("More complicated than a Fusion Reactor. Seriously")
+ .addInfo("But you know this by now, right?")
+ .addInfo("Works as fast as 32 Large Heat Exchangers")
+ .addSeparator()
+ .addInfo("Inputs are Hot Coolant or Lava")
+ .addInfo("Outputs Coolant or Pahoehoe Lava and SH Steam/Steam")
+ .addInfo("Outputs SH Steam if input flow is equal to or above a certain value:")
+ .addInfo("Hot Coolant: 25,600 L/s, maximum 51,200 L/s, max output 10,240,000 SH Steam/s")
+ .addInfo("Lava: 32,000 L/s, maximum 64,000 L/s, max output 5,120,000 SH Steam/s")
+ .addInfo("A circuit in the controller lowers the SH Steam threshold and efficiency")
+ .addInfo("3.75% reduction and 1.5% efficiency loss per circuit config over 1")
+ .addSeparator()
+ .beginStructureBlock(5, 9, 5, false)
+ .addController("Front bottom")
+ .addCasingInfoMin("Reinforced Heat Exchanger Casing", 90, false)
+ .addOtherStructurePart("Tungstensteel Pipe Casing", "Center 3x5x3 (45 blocks)")
+ .addMaintenanceHatch("Any casing", 1)
+ .addInputHatch("Hot fluid, bottom center", 2)
+ .addInputHatch("Distilled water, any bottom layer casing", 1)
+ .addOutputHatch("Cold fluid, top center", 3)
+ .addOutputHatch("Steam/SH Steam, any bottom layer casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ superheated = aNBT.getBoolean("superheated");
+ super.loadNBTData(aNBT);
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ aNBT.setBoolean("superheated", superheated);
+ super.saveNBTData(aNBT);
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return CASING_INDEX;
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ protected IAlignmentLimits getInitialAlignmentLimits() {
+ return (d, r, f) -> !r.isUpsideDown() && !f.isVerticallyFliped();
+ }
+
+ @Override
+ public @NotNull CheckRecipeResult checkProcessing() {
+ if (mInputHotFluidHatch.getFluid() == null) return CheckRecipeResultRegistry.SUCCESSFUL;
+
+ int fluidAmountToConsume = mInputHotFluidHatch.getFluidAmount(); // how much fluid is in hatch
+
+ // The XL LHE works as fast as 32 regular LHEs. These are the comments from the original LHE,
+ // with changes where the values needed to change for the 32x speed multiplier
+ superheated_threshold = 128000; // default: must have 4000L -> 128000L per second to generate superheated steam
+ float efficiency = 1f; // default: operate at 100% efficiency with no integrated circuitry
+ int shs_reduction_per_config = 4800; // reduce threshold 150L -> 4800L per second per circuitry level (1-25)
+ float steam_output_multiplier = 20f; // default: multiply output by 4 * 10 (boosted x5)
+ float penalty = 0.0f; // penalty to apply to output based on circuitry level (1-25).
+ boolean do_lava = false;
+
+ // Do we have an integrated circuit with a valid configuration?
+ if (mInventory[1] != null && mInventory[1].getUnlocalizedName()
+ .startsWith("gt.integrated_circuit")) {
+ int circuit_config = mInventory[1].getItemDamage();
+ if (circuit_config >= 1 && circuit_config <= 25) {
+ // If so, apply the penalty and reduced threshold.
+ penalty = (circuit_config - 1) * penalty_per_config;
+ superheated_threshold -= (shs_reduction_per_config * (circuit_config - 1));
+ }
+ }
+ efficiency -= penalty;
+
+ // If we're working with lava, adjust the threshold and multipliers accordingly.
+ if (GT_ModHandler.isLava(mInputHotFluidHatch.getFluid())) {
+ steam_output_multiplier /= 5f; // lava is not boosted
+ superheated_threshold /= 4f; // unchanged
+ do_lava = true;
+ } else if (mInputHotFluidHatch.getFluid()
+ .isFluidEqual(FluidRegistry.getFluidStack("ic2hotcoolant", 1))) {
+ steam_output_multiplier /= 2f; // was boosted x2 on top of x5 -> total x10 -> nerf with this code back
+ // to 5x
+ superheated_threshold /= 5f; // 10x smaller since the Hot Things production in reactor is the same.
+ } else {
+ // If we're working with neither, fail out
+ superheated_threshold = 0;
+ return CheckRecipeResultRegistry.NO_RECIPE;
+ }
+
+ superheated = fluidAmountToConsume >= superheated_threshold; // set the internal superheated flag if we have
+ // enough hot fluid. Used in the
+ // onRunningTick method.
+ fluidAmountToConsume = Math.min(fluidAmountToConsume, superheated_threshold * 2); // Don't consume too much hot
+ // fluid per second, maximum
+ // is 2x SH threshold.
+ mInputHotFluidHatch.drain(fluidAmountToConsume, true);
+ this.mMaxProgresstime = 20;
+ this.lEUt = (long) (fluidAmountToConsume * steam_output_multiplier * efficiency);
+ if (do_lava) {
+ mOutputColdFluidHatch.fill(FluidRegistry.getFluidStack("ic2pahoehoelava", fluidAmountToConsume), true);
+ } else {
+ mOutputColdFluidHatch.fill(FluidRegistry.getFluidStack("ic2coolant", fluidAmountToConsume), true);
+ }
+ this.mEfficiencyIncrease = 80;
+ return CheckRecipeResultRegistry.SUCCESSFUL;
+ }
+
+ private int useWater(float input) {
+ water = water + input;
+ int usage = (int) water;
+ water = water - usage;
+ return usage;
+ }
+
+ @Override
+ public boolean onRunningTick(ItemStack aStack) {
+ if (this.lEUt > 0) {
+ int tGeneratedEU = (int) (this.lEUt * 2L * this.mEfficiency / 10000L); // APPROXIMATELY how much steam to
+ // generate.
+ if (tGeneratedEU > 0) {
+
+ if (superheated) tGeneratedEU /= 2; // We produce half as much superheated steam if necessary
+
+ int distilledConsumed = useWater(tGeneratedEU / 160f); // how much distilled water to consume
+ // tGeneratedEU = distilledConsumed * 160; // EXACTLY how much steam to generate, producing a perfect
+ // 1:160 ratio with distilled water consumption
+
+ FluidStack distilledStack = GT_ModHandler.getDistilledWater(distilledConsumed);
+ if (depleteInput(distilledStack)) // Consume the distilled water
+ {
+ if (superheated) {
+ addOutput(FluidRegistry.getFluidStack("ic2superheatedsteam", tGeneratedEU)); // Generate
+ // superheated
+ // steam
+ } else {
+ addOutput(GT_ModHandler.getSteam(tGeneratedEU)); // Generate regular steam
+ }
+ } else {
+ GT_Log.exp.println(this.mName + " had no more Distilled water!");
+ explodeMultiblock(); // Generate crater
+ }
+ }
+ return true;
+ }
+ return true;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_Adv_HeatExchanger> getStructureDefinition() {
+ return STRUCTURE_DEFINITION;
+ }
+
+ private void onCasingAdded() {
+ mCasingAmount++;
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mOutputColdFluidHatch = null;
+ mInputHotFluidHatch = null;
+ mCasingAmount = 0;
+ return checkPiece(STRUCTURE_PIECE_MAIN, 2, 5, 0) && mCasingAmount >= 90 && mMaintenanceHatches.size() == 1;
+ }
+
+ public boolean addColdFluidOutputToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) {
+ if (aTileEntity == null) return false;
+ IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+ if (aMetaTileEntity == null) return false;
+ if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Output) {
+ ((GT_MetaTileEntity_Hatch) aMetaTileEntity).updateTexture(aBaseCasingIndex);
+ mOutputColdFluidHatch = (GT_MetaTileEntity_Hatch_Output) aMetaTileEntity;
+ return true;
+ }
+ return false;
+ }
+
+ public boolean addHotFluidInputToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) {
+ if (aTileEntity == null) return false;
+ IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+ if (aMetaTileEntity == null) return false;
+ if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Input) {
+ ((GT_MetaTileEntity_Hatch) aMetaTileEntity).updateTexture(aBaseCasingIndex);
+ ((GT_MetaTileEntity_Hatch_Input) aMetaTileEntity).mRecipeMap = getRecipeMap();
+ mInputHotFluidHatch = (GT_MetaTileEntity_Hatch_Input) aMetaTileEntity;
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_Adv_HeatExchanger(this.mName);
+ }
+
+ @Override
+ public boolean isGivingInformation() {
+ return super.isGivingInformation();
+ }
+
+ @Override
+ public String[] getExtraInfoData() {
+ return new String[] {
+ StatCollector.translateToLocal("GT5U.multiblock.Progress") + ": "
+ + EnumChatFormatting.GREEN
+ + GT_Utility.formatNumbers(mProgresstime / 20)
+ + EnumChatFormatting.RESET
+ + " s / "
+ + EnumChatFormatting.YELLOW
+ + GT_Utility.formatNumbers(mMaxProgresstime / 20)
+ + EnumChatFormatting.RESET
+ + " s",
+ StatCollector.translateToLocal("GT5U.multiblock.usage") + " "
+ + StatCollector.translateToLocal("GT5U.LHE.steam")
+ + ": "
+ + (superheated ? EnumChatFormatting.RED : EnumChatFormatting.YELLOW)
+ + GT_Utility.formatNumbers(superheated ? -2 * lEUt : -lEUt)
+ + EnumChatFormatting.RESET
+ + " EU/t",
+ StatCollector.translateToLocal("GT5U.multiblock.problems") + ": "
+ + EnumChatFormatting.RED
+ + (getIdealStatus() - getRepairStatus())
+ + EnumChatFormatting.RESET
+ + " "
+ + StatCollector.translateToLocal("GT5U.multiblock.efficiency")
+ + ": "
+ + EnumChatFormatting.YELLOW
+ + mEfficiency / 100.0F
+ + EnumChatFormatting.RESET
+ + " %",
+ StatCollector.translateToLocal("GT5U.LHE.superheated") + ": "
+ + (superheated ? EnumChatFormatting.RED : EnumChatFormatting.BLUE)
+ + superheated
+ + EnumChatFormatting.RESET,
+ StatCollector.translateToLocal("GT5U.LHE.superheated") + " "
+ + StatCollector.translateToLocal("GT5U.LHE.threshold")
+ + ": "
+ + EnumChatFormatting.GREEN
+ + GT_Utility.formatNumbers(superheated_threshold)
+ + EnumChatFormatting.RESET };
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(STRUCTURE_PIECE_MAIN, stackSize, hintsOnly, 2, 5, 0);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Heat Exchanger";
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 0;
+ }
+
+ private static Block sFrame;
+
+ public static Block getFrame() {
+ if (sFrame == null) {
+ sFrame = BlockBaseModular.getMaterialBlock(ALLOY.TALONITE, BlockTypes.FRAME);
+ }
+ return sFrame;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_Implosion.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_Implosion.java
new file mode 100644
index 0000000000..432ce23e74
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/advanced/GregtechMetaTileEntity_Adv_Implosion.java
@@ -0,0 +1,177 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing.advanced;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.GregTech_API.sBlockCasings4;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import net.minecraft.item.ItemStack;
+
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.SoundResource;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_Adv_Implosion
+ extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_Adv_Implosion> {
+
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_Adv_Implosion> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_Adv_Implosion(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_Adv_Implosion(String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_Adv_Implosion(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Implosion Compressor";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Factory Grade Advanced Implosion Compressor")
+ .addInfo("Speed: +100% | EU Usage: 100% | Parallel: ((Tier/2)+1)")
+ .addInfo("Constructed exactly the same as a normal Implosion Compressor")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 3, 3, true)
+ .addController("Front center")
+ .addCasingInfoMin("Robust TungstenSteel Casing", 10, false)
+ .addInputBus("Any casing", 1)
+ .addOutputBus("Any casing", 1)
+ .addEnergyHatch("Any casing", 1)
+ .addMaintenanceHatch("Any casing", 1)
+ .addMufflerHatch("Any casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_Adv_Implosion> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_Adv_Implosion>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC" }, { "C~C", "C-C", "CCC" }, { "CCC", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ ofChain(
+ buildHatchAdder(GregtechMetaTileEntity_Adv_Implosion.class)
+ .atLeast(InputBus, OutputBus, Maintenance, Energy, Muffler)
+ .casingIndex(48)
+ .dot(1)
+ .build(),
+ onElementPass(x -> ++x.mCasing, ofBlock(sBlockCasings4, 0))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 1, 0);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ return checkPiece(mName, 1, 1, 0) && mCasing >= 10 && checkHatch();
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return 48;
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return RecipeMaps.implosionRecipes;
+ }
+
+ @Override
+ public int getRecipeCatalystPriority() {
+ return -1;
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic().setSpeedBonus(1F / 2F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ protected SoundResource getProcessStartSound() {
+ return SoundResource.RANDOM_EXPLODE;
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiAdvImplosion;
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return (GT_Utility.getTier(this.getMaxInputVoltage()) / 2 + 1);
+ }
+
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/steam/GregtechMetaTileEntity_SteamCompressor.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/steam/GregtechMetaTileEntity_SteamCompressor.java
new file mode 100644
index 0000000000..0845c7f061
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/steam/GregtechMetaTileEntity_SteamCompressor.java
@@ -0,0 +1,156 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing.steam;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.GregTech_API.sBlockCasings1;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import javax.annotation.Nonnull;
+
+import net.minecraft.item.ItemStack;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.Textures;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.objects.GT_RenderedTexture;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_OverclockCalculator;
+import gregtech.api.util.GT_Recipe;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_SteamMultiBase;
+
+public class GregtechMetaTileEntity_SteamCompressor
+ extends GregtechMeta_SteamMultiBase<GregtechMetaTileEntity_SteamCompressor> implements ISurvivalConstructable {
+
+ private String mCasingName = "Bronze Plated Bricks";
+ private static IStructureDefinition<GregtechMetaTileEntity_SteamCompressor> STRUCTURE_DEFINITION = null;
+ private int mCasing;
+
+ public GregtechMetaTileEntity_SteamCompressor(String aName) {
+ super(aName);
+ }
+
+ public GregtechMetaTileEntity_SteamCompressor(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity arg0) {
+ return new GregtechMetaTileEntity_SteamCompressor(this.mName);
+ }
+
+ @Override
+ protected GT_RenderedTexture getFrontOverlay() {
+ return new GT_RenderedTexture(Textures.BlockIcons.OVERLAY_FRONT_STEAM_COMPRESSOR);
+ }
+
+ @Override
+ protected GT_RenderedTexture getFrontOverlayActive() {
+ return new GT_RenderedTexture(Textures.BlockIcons.OVERLAY_FRONT_STEAM_COMPRESSOR_ACTIVE);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Compressor";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Steam Compressor")
+ .addInfo("33.3% faster than using a single block Steam Compressor.")
+ .addInfo("Uses only 66.6% of the steam/s compared to a single block Steam Compressor.")
+ .addInfo("Compresses up to " + getMaxParallelRecipes() + " things at a time")
+ .addSeparator()
+ .beginStructureBlock(3, 3, 4, true)
+ .addController("Front center")
+ .addCasingInfoMin(mCasingName, 28, false)
+ .addOtherStructurePart(TT_steaminputbus, "Any casing", 1)
+ .addOtherStructurePart(TT_steamoutputbus, "Any casing", 1)
+ .addOtherStructurePart(TT_steamhatch, "Any casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_SteamCompressor> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_SteamCompressor>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC", "CCC" }, { "C~C", "C-C", "C-C", "CCC" },
+ { "CCC", "CCC", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ ofChain(
+ buildSteamInput(GregtechMetaTileEntity_SteamCompressor.class).casingIndex(10)
+ .dot(1)
+ .build(),
+ buildHatchAdder(GregtechMetaTileEntity_SteamCompressor.class)
+ .atLeast(SteamHatchElement.InputBus_Steam, SteamHatchElement.OutputBus_Steam)
+ .casingIndex(10)
+ .dot(1)
+ .build(),
+ onElementPass(x -> ++x.mCasing, ofBlock(sBlockCasings1, 10))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ return survivialBuildPiece(mName, stackSize, 1, 1, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ fixAllMaintenanceIssue();
+ return checkPiece(mName, 1, 1, 0) && mCasing >= 28;
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 8;
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return RecipeMaps.compressorRecipes;
+ }
+
+ // note that a basic steam machine has .setEUtDiscount(2F).setSpeedBoost(2F). So these are bonuses.
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic() {
+
+ @Override
+ @Nonnull
+ protected GT_OverclockCalculator createOverclockCalculator(@NotNull GT_Recipe recipe) {
+ return GT_OverclockCalculator.ofNoOverclock(recipe)
+ .setEUtDiscount(1.33F)
+ .setSpeedBoost(1.5F);
+ }
+ }.setMaxParallel(getMaxParallelRecipes());
+ }
+
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/steam/GregtechMetaTileEntity_SteamMacerator.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/steam/GregtechMetaTileEntity_SteamMacerator.java
new file mode 100644
index 0000000000..dce362fa14
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/processing/steam/GregtechMetaTileEntity_SteamMacerator.java
@@ -0,0 +1,165 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.processing.steam;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.GregTech_API.sBlockCasings1;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import javax.annotation.Nonnull;
+
+import net.minecraft.item.ItemStack;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.ItemList;
+import gregtech.api.enums.Textures;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.objects.GT_RenderedTexture;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_OverclockCalculator;
+import gregtech.api.util.GT_Recipe;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_SteamMultiBase;
+
+public class GregtechMetaTileEntity_SteamMacerator
+ extends GregtechMeta_SteamMultiBase<GregtechMetaTileEntity_SteamMacerator> implements ISurvivalConstructable {
+
+ private String mCasingName = "Bronze Plated Bricks";
+ private static IStructureDefinition<GregtechMetaTileEntity_SteamMacerator> STRUCTURE_DEFINITION = null;
+ private int mCasing;
+
+ public GregtechMetaTileEntity_SteamMacerator(String aName) {
+ super(aName);
+ }
+
+ public GregtechMetaTileEntity_SteamMacerator(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity arg0) {
+ return new GregtechMetaTileEntity_SteamMacerator(this.mName);
+ }
+
+ @Override
+ protected GT_RenderedTexture getFrontOverlay() {
+ return new GT_RenderedTexture(Textures.BlockIcons.OVERLAY_TOP_STEAM_MACERATOR);
+ }
+
+ @Override
+ protected GT_RenderedTexture getFrontOverlayActive() {
+ return new GT_RenderedTexture(Textures.BlockIcons.OVERLAY_TOP_STEAM_MACERATOR_ACTIVE);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Macerator";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ if (mCasingName.contains("gt.blockcasings")) {
+ mCasingName = ItemList.Casing_BronzePlatedBricks.get(1)
+ .getDisplayName();
+ }
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Steam Macerator")
+ .addInfo("33.3% faster than using a single block Steam Macerator.")
+ .addInfo("Uses only 66.6% of the steam/s required compared to a single block Steam Macerator.")
+ .addInfo("Macerates up to " + getMaxParallelRecipes() + " things at a time")
+ .addSeparator()
+ .beginStructureBlock(3, 3, 3, true)
+ .addController("Front center")
+ .addCasingInfoMin(mCasingName, 14, false)
+ .addOtherStructurePart(TT_steaminputbus, "Any casing", 1)
+ .addOtherStructurePart(TT_steamoutputbus, "Any casing", 1)
+ .addOtherStructurePart(TT_steamhatch, "Any casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_SteamMacerator> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_SteamMacerator>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC" }, { "C~C", "C-C", "CCC" }, { "CCC", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ ofChain(
+ buildSteamInput(GregtechMetaTileEntity_SteamMacerator.class).casingIndex(10)
+ .dot(1)
+ .build(),
+ buildHatchAdder(GregtechMetaTileEntity_SteamMacerator.class)
+ .atLeast(SteamHatchElement.InputBus_Steam, SteamHatchElement.OutputBus_Steam)
+ .casingIndex(10)
+ .dot(1)
+ .build(),
+ onElementPass(x -> ++x.mCasing, ofBlock(sBlockCasings1, 10))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ return survivialBuildPiece(mName, stackSize, 1, 1, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ fixAllMaintenanceIssue();
+ return checkPiece(mName, 1, 1, 0) && mCasing >= 14;
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 8;
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return RecipeMaps.maceratorRecipes;
+ }
+
+ // note that a basic steam machine has .setEUtDiscount(2F).setSpeedBoost(2F). So these are bonuses.
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic() {
+
+ @Override
+ @Nonnull
+ protected GT_OverclockCalculator createOverclockCalculator(@NotNull GT_Recipe recipe) {
+ return GT_OverclockCalculator.ofNoOverclock(recipe)
+ .setEUtDiscount(1.33F)
+ .setSpeedBoost(1.5F);
+ }
+
+ }.setMaxParallel(getMaxParallelRecipes());
+ }
+
+ @Override
+ public int getItemOutputLimit() {
+ return 1;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GT4Entity_AutoCrafter.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GT4Entity_AutoCrafter.java
new file mode 100644
index 0000000000..6cae5e4bcd
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GT4Entity_AutoCrafter.java
@@ -0,0 +1,196 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import net.minecraft.item.ItemStack;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.TAE;
+import gregtech.api.enums.Textures;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.metatileentity.MetaTileEntity;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+
+public class GT4Entity_AutoCrafter extends GregtechMeta_MultiBlockBase<GT4Entity_AutoCrafter>
+ implements ISurvivalConstructable {
+
+ protected GT_Recipe lastRecipeToBuffer;
+ private int casing;
+ private static IStructureDefinition<GT4Entity_AutoCrafter> STRUCTURE_DEFINITION = null;
+
+ public GT4Entity_AutoCrafter(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GT4Entity_AutoCrafter(String mName) {
+ super(mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Assembler";
+ }
+
+ @Override
+ public MetaTileEntity newMetaEntity(IGregTechTileEntity tileEntity) {
+ return new GT4Entity_AutoCrafter(this.mName);
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack itemStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiAutoCrafter;
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Highly Advanced Assembling Machine")
+ .addInfo("200% faster than using single block machines of the same voltage")
+ .addInfo("Processes two items per voltage tier")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 3, 3, true)
+ .addController("Front Center")
+ .addCasingInfoRange("Bulk Production Frame", 10, 25, false)
+ .addInputBus("Any Casing", 1)
+ .addOutputBus("Any Casing", 1)
+ .addInputHatch("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return Textures.BlockIcons.OVERLAY_FRONT_DISASSEMBLER_ACTIVE;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return Textures.BlockIcons.OVERLAY_FRONT_DISASSEMBLER;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return TAE.getIndexFromPage(0, 10);
+ }
+
+ @Override
+ public IStructureDefinition<GT4Entity_AutoCrafter> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GT4Entity_AutoCrafter>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC" }, { "C~C", "C-C", "CCC" }, { "CCC", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GT4Entity_AutoCrafter.class)
+ .atLeast(InputBus, OutputBus, InputHatch, Maintenance, Energy, Muffler)
+ .casingIndex(TAE.getIndexFromPage(0, 10))
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.casing, ofBlock(ModBlocks.blockCasings2Misc, 12))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack itemStack, boolean hintsOnly) {
+ buildPiece(mName, itemStack, hintsOnly, 1, 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack itemStack, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, itemStack, 1, 1, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity baseMetaTileEntity, ItemStack itemStack) {
+ casing = 0;
+ return checkPiece(mName, 1, 1, 0) && casing >= 10 && checkHatch();
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return RecipeMaps.assemblerRecipes;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic().setSpeedBonus(1F / 3F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 2 * (Math.max(1, GT_Utility.getTier(getMaxInputVoltage())));
+ }
+
+ @Override
+ public String[] getExtraInfoData() {
+ final String running = (this.mMaxProgresstime > 0 ? "Auto-Crafter running" : "Auto-Crafter stopped");
+ final String maintenance = (this.getIdealStatus() == this.getRepairStatus() ? "No Maintenance issues"
+ : "Needs Maintenance");
+ String tSpecialText;
+
+ if (lastRecipeToBuffer != null && lastRecipeToBuffer.mOutputs[0].getDisplayName() != null) {
+ tSpecialText = "Currently processing: " + lastRecipeToBuffer.mOutputs[0].getDisplayName();
+ } else {
+ tSpecialText = "Currently processing: Nothing";
+ }
+
+ return new String[] { "Large Scale Auto-Assembler v1.01c", running, maintenance, tSpecialText };
+ }
+
+ @Override
+ public boolean supportsInputSeparation() {
+ return true;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GT4Entity_ThermalBoiler.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GT4Entity_ThermalBoiler.java
new file mode 100644
index 0000000000..b7a4afb878
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GT4Entity_ThermalBoiler.java
@@ -0,0 +1,353 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import java.util.stream.Stream;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.minecraft.init.Blocks;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.fluids.Fluid;
+import net.minecraftforge.fluids.FluidRegistry;
+import net.minecraftforge.fluids.FluidStack;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.GT_Values;
+import gregtech.api.enums.ItemList;
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.metatileentity.MetaTileEntity;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.util.GT_Log;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_ParallelHelper;
+import gregtech.api.util.GT_Recipe;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.minecraft.FluidUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GT4Entity_ThermalBoiler extends GregtechMeta_MultiBlockBase<GT4Entity_ThermalBoiler>
+ implements ISurvivalConstructable {
+
+ private int mCasing;
+ private static IStructureDefinition<GT4Entity_ThermalBoiler> STRUCTURE_DEFINITION = null;
+
+ private static final int lavaFilterResilience = 30; // Damage lava filter with 1/n probability every operation.
+ private int dryHeatCounter = 0; // Counts up to dryHeatMaximum to check for explosion conditions.
+ private static final int dryHeatMaximum = 10; // 10 consecutive operations without water = BOOM
+
+ private static final Item itemLavaFilter = ItemList.Component_LavaFilter.getItem();
+ private static final Item itemObsidian = Item.getItemFromBlock(Blocks.obsidian);
+ private static final Fluid fluidWater = FluidRegistry.WATER;
+ private static final Fluid fluidDistilledWater = FluidUtils.getDistilledWater(1)
+ .getFluid();
+ private static final Fluid fluidSteam = FluidUtils.getSteam(1)
+ .getFluid();
+ private static final Fluid fluidSHSteam = FluidUtils.getSuperHeatedSteam(1)
+ .getFluid();
+
+ public GT4Entity_ThermalBoiler(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GT4Entity_ThermalBoiler(String mName) {
+ super(mName);
+ }
+
+ @Override
+ public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GT4Entity_ThermalBoiler(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Boiler";
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return (aStack != null && aStack.getItem() == itemLavaFilter) ? 1 : 0;
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return GTPPRecipeMaps.thermalBoilerRecipes;
+ }
+
+ @Override
+ protected boolean filtersFluid() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsVoidProtection() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsBatchMode() {
+ return false;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic() {
+
+ // Only test against the first fluid input in the recipe.
+ // We still want to run if we lack water (and subsequently explode).
+ @NotNull
+ @Override
+ protected Stream<GT_Recipe> findRecipeMatches(@Nullable RecipeMap<?> map) {
+ if (lastRecipe != null && depleteInput(lastRecipe.mFluidInputs[0], true)) {
+ return Stream.of(lastRecipe);
+ }
+ if (map == null) {
+ return Stream.empty();
+ }
+ return map.getAllRecipes()
+ .stream()
+ .filter(recipe -> depleteInput(recipe.mFluidInputs[0], true));
+ }
+
+ @NotNull
+ @Override
+ protected GT_ParallelHelper createParallelHelper(@Nonnull GT_Recipe recipe) {
+ GT_Recipe adjustedRecipe = recipe.copy();
+
+ // Hack the recipe logic to not consume water, so that we can explode.
+ for (FluidStack inputFluid : adjustedRecipe.mFluidInputs) {
+ if (inputFluid != null
+ && (inputFluid.getFluid() == fluidWater || inputFluid.getFluid() == fluidDistilledWater)) {
+ inputFluid.amount = 0;
+ }
+ }
+
+ // If we don't have a lava filter, remove non-obsidian outputs
+ // so that output space for them is not required if void protection is on.
+ if (!findLavaFilter()) {
+ for (ItemStack outputItem : adjustedRecipe.mOutputs) {
+ if (outputItem != null && outputItem.getItem() != itemObsidian) {
+ outputItem.stackSize = 0;
+ }
+ }
+ }
+ return super.createParallelHelper(adjustedRecipe);
+ }
+ };
+ }
+
+ @Override
+ public @NotNull CheckRecipeResult checkProcessing() {
+ // super.checkProcessing() instantly sets efficiency to maximum, override this.
+ int efficiency = mEfficiency;
+ CheckRecipeResult result = super.checkProcessing();
+ if (result.wasSuccessful()) {
+ mEfficiency = efficiency;
+ mEfficiencyIncrease = mMaxProgresstime * getEfficiencyIncrease();
+
+ // Adjust steam output based on efficiency.
+ if (mOutputFluids != null) {
+ for (FluidStack outputFluid : mOutputFluids) {
+ if (outputFluid != null
+ && (outputFluid.getFluid() == fluidSteam || outputFluid.getFluid() == fluidSHSteam)) {
+
+ // Purely for display reasons, we don't actually make any EU.
+ if (outputFluid.getFluid() == fluidSteam) {
+ lEUt = outputFluid.amount / mMaxProgresstime / 2;
+ } else {
+ lEUt = outputFluid.amount / mMaxProgresstime;
+ }
+
+ // Adjust steam output based on efficiency.
+ // TODO: This is not reflected in the GUI while the player has it open??
+ if (mEfficiency < getMaxEfficiency(null)) {
+ outputFluid.amount = Math
+ .max(1, (outputFluid.amount * mEfficiency) / getMaxEfficiency(null));
+ }
+
+ // Consume water to run recipe.
+ if (!useWater(outputFluid.amount)) {
+ outputFluid.amount = 0;
+ lEUt = 0;
+ }
+ }
+ }
+ }
+
+ // Remove non-obsidian outputs if we can't damage lava filter.
+ if (mOutputItems != null && mOutputItems.length > 0) {
+ if (!damageLavaFilter()) {
+ for (ItemStack outputItem : mOutputItems) {
+ if (outputItem != null && outputItem.getItem() != itemObsidian) {
+ outputItem.stackSize = 0;
+ }
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ private boolean findLavaFilter() {
+ if (getControllerSlot() == null) {
+ for (var bus : mInputBusses) {
+ for (ItemStack stack : bus.mInventory) {
+ if (stack != null && stack.getItem() == itemLavaFilter) {
+ setGUIItemStack(stack);
+ return true;
+ }
+ }
+ }
+ return false;
+ } else {
+ return getControllerSlot().getItem() == itemLavaFilter;
+ }
+ }
+
+ private boolean damageLavaFilter() {
+ if (!findLavaFilter()) return false;
+ if (getBaseMetaTileEntity().getRandomNumber(lavaFilterResilience) > 0) return true;
+
+ ItemStack filter = getControllerSlot();
+ if (filter.attemptDamageItem(1, getBaseMetaTileEntity().getWorld().rand)) {
+ mInventory[1] = null;
+ }
+ return true;
+ }
+
+ private boolean useWater(int steamAmount) {
+ // Round up to not dupe decimal amounts of water.
+ int waterAmount = Math.floorDiv(steamAmount + GT_Values.STEAM_PER_WATER - 1, GT_Values.STEAM_PER_WATER);
+ if (depleteInput(FluidUtils.getWater(waterAmount)) || depleteInput(FluidUtils.getDistilledWater(waterAmount))) {
+ dryHeatCounter = 0;
+ return true;
+ } else {
+ // Add some leniency with explosions.
+ if (dryHeatCounter < dryHeatMaximum) {
+ ++dryHeatCounter;
+ } else {
+ GT_Log.exp.println(this.mName + " was too hot and had no more Water!");
+ explodeMultiblock(); // Generate crater
+ }
+ return false;
+ }
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 1;
+ }
+
+ public int getEfficiencyIncrease() {
+ return 12;
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiThermalBoiler;
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Thermal Boiler Controller")
+ .addInfo("Converts Water & Heat into Steam")
+ .addInfo("Filters raw materials from lava")
+ .addInfo("Explodes if water is not supplied")
+ .addInfo("Consult user manual for more information")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .beginStructureBlock(3, 3, 3, true)
+ .addController("Front Center")
+ .addCasingInfoMin("Thermal Containment Casings", 10, false)
+ .addInputBus("Any Casing", 1)
+ .addOutputBus("Any Casing", 1)
+ .addInputHatch("Any Casing", 1)
+ .addOutputHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return TAE.GTPP_INDEX(1);
+ }
+
+ @Override
+ public IStructureDefinition<GT4Entity_ThermalBoiler> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GT4Entity_ThermalBoiler>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC" }, { "C~C", "C-C", "CCC" }, { "CCC", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GT4Entity_ThermalBoiler.class)
+ .atLeast(InputBus, OutputBus, InputHatch, OutputHatch, Maintenance, Muffler)
+ .casingIndex(TAE.getIndexFromPage(0, 1))
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings2Misc, 11))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 1, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ return checkPiece(mName, 1, 1, 0) && mCasing >= 10 && checkHatch();
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMTE_ElementalDuplicator.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMTE_ElementalDuplicator.java
new file mode 100644
index 0000000000..d835d9be4c
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMTE_ElementalDuplicator.java
@@ -0,0 +1,352 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.lazy;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+import static gregtech.api.util.GT_Utility.filterValidMTEs;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import net.minecraft.block.Block;
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits;
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_ElementalDataOrbHolder;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMTE_ElementalDuplicator extends GregtechMeta_MultiBlockBase<GregtechMTE_ElementalDuplicator>
+ implements ISurvivalConstructable {
+
+ private final ArrayList<GT_MetaTileEntity_Hatch_ElementalDataOrbHolder> mReplicatorDataOrbHatches = new ArrayList<>();
+ private static final int CASING_TEXTURE_ID = TAE.getIndexFromPage(0, 3);
+ private int mCasing = 0;
+
+ public GregtechMTE_ElementalDuplicator(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMTE_ElementalDuplicator(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMTE_ElementalDuplicator(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Replicator";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Produces Elemental Material from UU Matter")
+ .addInfo("Speed: +100% | EU Usage: 100% | Parallel: 8 * Tier")
+ .addInfo("Maximum 1x of each bus/hatch.")
+ .addInfo("Requires circuit 1-16 in your Data Orb Repository")
+ .addInfo("depending on what Data Orb you want to prioritize")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(9, 6, 9, true)
+ .addController("Top Center")
+ .addCasingInfoMin("Elemental Confinement Shell", 138, false)
+ .addCasingInfoMin("Matter Fabricator Casing", 24, false)
+ .addCasingInfoMin("Particle Containment Casing", 24, false)
+ .addCasingInfoMin("Matter Generation Coil", 24, false)
+ .addCasingInfoMin("High Voltage Current Capacitor", 20, false)
+ .addCasingInfoMin("Resonance Chamber III", 24, false)
+ .addCasingInfoMin("Modulator III", 16, false)
+ .addOtherStructurePart("Data Orb Repository", "1x", 1)
+ .addInputHatch("Any 1 dot hint", 1)
+ .addOutputBus("Any 1 dot hint", 1)
+ .addOutputHatch("Any 1 dot hint", 1)
+ .addEnergyHatch("Any 1 dot hint", 1)
+ .addMaintenanceHatch("Any 1 dot hint", 1)
+ .addMufflerHatch("Any 1 dot hint", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ private static final String STRUCTURE_PIECE_MAIN = "main";
+ private static IStructureDefinition<GregtechMTE_ElementalDuplicator> STRUCTURE_DEFINITION = null;
+
+ @Override
+ public IStructureDefinition<GregtechMTE_ElementalDuplicator> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMTE_ElementalDuplicator>builder()
+
+ // h = Hatch
+ // c = Casing
+
+ // a = MF Casing 1
+ // b = Matter Gen Coil
+
+ // d = Current Capacitor
+ // e = Particle
+
+ // f = Resonance III
+ // g = Modulator III
+
+ .addShape(
+ STRUCTURE_PIECE_MAIN,
+ (new String[][] {
+ { " ccc ", " ccccc ", " ccccccc ", "ccchhhccc", "ccch~hccc", "ccchhhccc", " ccccccc ",
+ " ccccc ", " ccc " },
+ { " cac ", " abfba ", " abfgfba ", "cbfgdgfbc", "afgdddgfa", "cbfgdgfbc", " abfgfba ",
+ " abfba ", " cac " },
+ { " cec ", " e e ", " e e ", "c d c", "e ddd e", "c d c", " e e ",
+ " e e ", " cec " },
+ { " cec ", " e e ", " e e ", "c d c", "e ddd e", "c d c", " e e ",
+ " e e ", " cec " },
+ { " cac ", " abfba ", " abfgfba ", "cbfgdgfbc", "afgdddgfa", "cbfgdgfbc", " abfgfba ",
+ " abfba ", " cac " },
+ { " ccc ", " ccccc ", " ccccccc ", "ccchhhccc", "ccchhhccc", "ccchhhccc", " ccccccc ",
+ " ccccc ", " ccc " }, }))
+ .addElement('a', ofBlock(getCasingBlock4(), getCasingMeta6()))
+ .addElement('b', ofBlock(getCasingBlock4(), getCasingMeta7()))
+ .addElement('d', ofBlock(getCasingBlock2(), getCasingMeta2()))
+ .addElement('e', ofBlock(getCasingBlock2(), getCasingMeta3()))
+ .addElement('f', ofBlock(getCasingBlock3(), getCasingMeta4()))
+ .addElement('g', ofBlock(getCasingBlock3(), getCasingMeta5()))
+ .addElement('c', lazy(t -> onElementPass(x -> ++x.mCasing, ofBlock(getCasingBlock(), getCasingMeta()))))
+ .addElement(
+ 'h',
+ lazy(
+ t -> ofChain(
+ buildHatchAdder(GregtechMTE_ElementalDuplicator.class)
+ .atLeast(InputHatch, OutputBus, OutputHatch, Maintenance, Muffler, Energy)
+ .casingIndex(getCasingTextureIndex())
+ .dot(1)
+ .build(),
+ buildHatchAdder(GregtechMTE_ElementalDuplicator.class)
+ .hatchClass(GT_MetaTileEntity_Hatch_ElementalDataOrbHolder.class)
+ .shouldReject(x -> x.mReplicatorDataOrbHatches.size() >= 1)
+ .adder(GregtechMTE_ElementalDuplicator::addDataOrbHatch)
+ .casingIndex(getCasingTextureIndex())
+ .dot(1)
+ .build(),
+ onElementPass(x -> ++x.mCasing, ofBlock(getCasingBlock(), getCasingMeta())))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(STRUCTURE_PIECE_MAIN, stackSize, hintsOnly, 4, 4, 0);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ boolean aDidBuild = checkPiece(STRUCTURE_PIECE_MAIN, 4, 4, 0);
+ if (this.mInputHatches.size() != 1 || (this.mOutputBusses.size() != 1 && this.mOutputHatches.size() != 0)
+ || this.mEnergyHatches.size() != 1
+ || this.mReplicatorDataOrbHatches.size() != 1) {
+ return false;
+ }
+ log("Casings: " + mCasing);
+ return aDidBuild && mCasing >= 138 && checkHatch();
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack itemStack, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(STRUCTURE_PIECE_MAIN, itemStack, 4, 4, 0, elementBudget, env, false, true);
+ }
+
+ protected static int getCasingTextureIndex() {
+ return CASING_TEXTURE_ID;
+ }
+
+ protected static Block getCasingBlock() {
+ return ModBlocks.blockCasings5Misc;
+ }
+
+ protected static Block getCasingBlock2() {
+ return ModBlocks.blockSpecialMultiCasings;
+ }
+
+ protected static Block getCasingBlock3() {
+ return ModBlocks.blockSpecialMultiCasings2;
+ }
+
+ protected static Block getCasingBlock4() {
+ return ModBlocks.blockCasingsMisc;
+ }
+
+ protected static int getCasingMeta() {
+ return 3;
+ }
+
+ protected static int getCasingMeta2() {
+ return 12;
+ }
+
+ protected static int getCasingMeta3() {
+ return 13;
+ }
+
+ protected static int getCasingMeta4() {
+ return 2;
+ }
+
+ protected static int getCasingMeta5() {
+ return 6;
+ }
+
+ protected static int getCasingMeta6() {
+ return 9;
+ }
+
+ protected static int getCasingMeta7() {
+ return 8;
+ }
+
+ private boolean addDataOrbHatch(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) {
+ if (aTileEntity == null) {
+ return false;
+ } else {
+ IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+ if (aMetaTileEntity == null) {
+ return false;
+ }
+ if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_ElementalDataOrbHolder) {
+ try {
+ return addToMachineListInternal(mReplicatorDataOrbHatches, aMetaTileEntity, aBaseCasingIndex);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected IAlignmentLimits getInitialAlignmentLimits() {
+ return (d, r, f) -> d == ForgeDirection.UP;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return CASING_TEXTURE_ID;
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return RecipeMaps.replicatorRecipes;
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(final ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic().setSpeedBonus(1F / 2F)
+ .enablePerfectOverclock()
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ protected void setupProcessingLogic(ProcessingLogic logic) {
+ super.setupProcessingLogic(logic);
+ for (GT_MetaTileEntity_Hatch_ElementalDataOrbHolder hatch : filterValidMTEs(mReplicatorDataOrbHatches)) {
+ ItemStack orb = hatch.getOrbByCircuit();
+ logic.setSpecialSlotItem(orb);
+ break;
+ }
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return (8 * GT_Utility.getTier(this.getMaxInputVoltage()));
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiMolecularTransformer;
+ }
+
+ @Override
+ public int getDamageToComponent(final ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {
+ if (aBaseMetaTileEntity.isServerSide()) {
+ if (this.mUpdate == 1 || this.mStartUpCheck == 1) {
+ this.mReplicatorDataOrbHatches.clear();
+ }
+ }
+ super.onPostTick(aBaseMetaTileEntity, aTick);
+ }
+
+ @Override
+ public ArrayList<ItemStack> getStoredInputs() {
+ ArrayList<ItemStack> tItems = super.getStoredInputs();
+ for (GT_MetaTileEntity_Hatch_ElementalDataOrbHolder tHatch : filterValidMTEs(mReplicatorDataOrbHatches)) {
+ tItems.add(tHatch.getOrbByCircuit());
+ }
+ tItems.removeAll(Collections.singleton(null));
+ return tItems;
+ }
+
+ @Override
+ public boolean doesBindPlayerInventory() {
+ return false;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMTE_FrothFlotationCell.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMTE_FrothFlotationCell.java
new file mode 100644
index 0000000000..8f807b94fd
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMTE_FrothFlotationCell.java
@@ -0,0 +1,287 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import java.util.List;
+import java.util.Objects;
+
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.StatCollector;
+import net.minecraftforge.common.util.Constants;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits;
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+import com.gtnewhorizons.modularui.api.screen.ModularWindow;
+import com.gtnewhorizons.modularui.api.screen.UIBuildContext;
+import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget;
+
+import gregtech.api.enums.SoundResource;
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.recipe.check.SimpleCheckRecipeResult;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Recipe;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.material.Material;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+import gtPlusPlus.xmod.gregtech.common.helpers.FlotationRecipeHandler;
+
+public class GregtechMTE_FrothFlotationCell extends GregtechMeta_MultiBlockBase<GregtechMTE_FrothFlotationCell>
+ implements ISurvivalConstructable {
+
+ private int mCasing;
+ private static IStructureDefinition<GregtechMTE_FrothFlotationCell> STRUCTURE_DEFINITION = null;
+
+ public GregtechMTE_FrothFlotationCell(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMTE_FrothFlotationCell(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMTE_FrothFlotationCell(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Flotation Cell";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Process that milled ore!")
+ .addInfo("You can only ever process one type of material per controller")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(7, 9, 7, true)
+ .addController("Front Center")
+ .addCasingInfoMin("Inconel Reinforced Casing", 68, false)
+ .addCasingInfoMin("Flotation Casing", 52, false)
+ .addInputBus("Bottom Casing", 1)
+ .addInputHatch("Bottom Casing", 1)
+ .addOutputHatch("Bottom Casing", 1)
+ .addEnergyHatch("Bottom Casing", 1)
+ .addMaintenanceHatch("Bottom Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ protected SoundResource getProcessStartSound() {
+ return SoundResource.IC2_MACHINES_ELECTROFURNACE_LOOP;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return TAE.getIndexFromPage(2, 1);
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return GTPPRecipeMaps.flotationCellRecipes;
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 1;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMTE_FrothFlotationCell> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMTE_FrothFlotationCell>builder()
+ .addShape(
+ mName,
+ new String[][] { { " ", " ", " X ", " X~X ", " X ", " ", " " },
+ { " ", " F ", " FFF ", " FF FF ", " FFF ", " F ", " " },
+ { " ", " F ", " F F ", " F F ", " F F ", " F ", " " },
+ { " ", " F ", " F F ", " F F ", " F F ", " F ", " " },
+ { " ", " F ", " F F ", " F F ", " F F ", " F ", " " },
+ { " ", " F ", " F F ", " F F ", " F F ", " F ", " " },
+ { " ", " F ", " F F ", " F F ", " F F ", " F ", " " },
+ { " CCC ", " CCCCC ", "CCCCCCC", "CCCCCCC", "CCCCCCC", " CCCCC ", " CCC " },
+ { " CCC ", " CCCCC ", "CCCCCCC", "CCCCCCC", "CCCCCCC", " CCCCC ", " CCC " }, })
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMTE_FrothFlotationCell.class)
+ .atLeast(InputBus, InputHatch, OutputHatch, Maintenance, Energy)
+ .casingIndex(getCasingTextureId())
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings3Misc, 1))))
+ .addElement('F', ofBlock(ModBlocks.blockSpecialMultiCasings, 9))
+ .addElement('X', ofBlock(ModBlocks.blockCasings3Misc, 1))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 3, 3, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 3, 3, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ return checkPiece(mName, 3, 3, 0) && mCasing >= 68 - 4 && checkHatch();
+ }
+
+ @Override
+ protected IAlignmentLimits getInitialAlignmentLimits() {
+ return (d, r, f) -> d == ForgeDirection.UP;
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiFrothFlotationCell;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic() {
+
+ @NotNull
+ @Override
+ protected CheckRecipeResult validateRecipe(@NotNull GT_Recipe recipe) {
+ /*
+ * Material checks Makes sure we can only ever use one type of material in this flotation cell. We used
+ * to depend on Alk's hash, but it's unreliable and user-hostile So we're using unlocalized name of
+ * material now.
+ */
+ Material foundMaterial = FlotationRecipeHandler
+ .getMaterialOfMilledProduct(FlotationRecipeHandler.findMilledStack(recipe));
+ String foundMaterialName = null;
+ if (foundMaterial != null) {
+ foundMaterialName = foundMaterial.getUnlocalizedName();
+ }
+
+ if (foundMaterialName == null) {
+ return CheckRecipeResultRegistry.NO_RECIPE;
+ }
+
+ // Set material locked for this controller
+ if (lockedMaterialName == null) {
+ lockedMaterialName = foundMaterialName;
+ }
+
+ // Check material match
+ if (!Objects.equals(lockedMaterialName, foundMaterialName)) {
+ return SimpleCheckRecipeResult.ofFailure("machine_locked_to_different_recipe");
+ }
+ return CheckRecipeResultRegistry.SUCCESSFUL;
+ }
+ }.enablePerfectOverclock();
+ }
+
+ /*
+ * Handle NBT
+ */
+
+ private String lockedMaterialName = null;
+
+ @Override
+ public void setItemNBT(NBTTagCompound aNBT) {
+ if (lockedMaterialName != null) {
+ aNBT.setString("lockedMaterialName", lockedMaterialName);
+ }
+ super.setItemNBT(aNBT);
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ super.saveNBTData(aNBT);
+ if (lockedMaterialName != null) {
+ aNBT.setString("lockedMaterialName", lockedMaterialName);
+ }
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ if (aNBT.hasKey("lockedMaterialName", Constants.NBT.TAG_STRING)) {
+ lockedMaterialName = aNBT.getString("lockedMaterialName");
+ }
+ }
+
+ @Override
+ public void addAdditionalTooltipInformation(ItemStack stack, List<String> tooltip) {
+ if (stack.hasTagCompound() && stack.getTagCompound()
+ .hasKey("lockedMaterialName")) {
+ tooltip.add(
+ StatCollector.translateToLocal("tooltip.flotationCell.lockedTo") + " "
+ + StatCollector.translateToLocal(
+ stack.getTagCompound()
+ .getString("lockedMaterialName")));
+ }
+ }
+
+ @Override
+ public String[] getExtraInfoData() {
+ return new String[] { "Locked material: " + lockedMaterialName };
+ }
+
+ @Override
+ public boolean isRecipeLockingEnabled() {
+ return lockedMaterialName != null && !lockedMaterialName.equals("");
+ }
+
+ @Override
+ public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) {
+ super.addUIWidgets(builder, buildContext);
+ builder.widget(new FakeSyncWidget.StringSyncer(() -> lockedMaterialName, val -> lockedMaterialName = val));
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMTE_NuclearReactor.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMTE_NuclearReactor.java
new file mode 100644
index 0000000000..2faccc9697
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMTE_NuclearReactor.java
@@ -0,0 +1,524 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Dynamo;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+import static gregtech.api.util.GT_StructureUtility.filterByMTETier;
+
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.common.util.ForgeDirection;
+import net.minecraftforge.fluids.FluidStack;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.TAE;
+import gregtech.api.enums.Textures;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.metatileentity.MetaTileEntity;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Dynamo;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Maintenance;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Muffler;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output;
+import gregtech.api.objects.GT_ItemStack;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.recipe.check.SimpleCheckRecipeResult;
+import gregtech.api.render.TextureFactory;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_OverclockCalculator;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.shutdown.ShutDownReasonRegistry;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.material.ELEMENT;
+import gtPlusPlus.core.material.nuclear.NUCLIDE;
+import gtPlusPlus.core.util.math.MathUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+
+public class GregtechMTE_NuclearReactor extends GregtechMeta_MultiBlockBase<GregtechMTE_NuclearReactor>
+ implements ISurvivalConstructable {
+
+ protected int mFuelRemaining = 0;
+
+ private int mCasing;
+ private static IStructureDefinition<GregtechMTE_NuclearReactor> STRUCTURE_DEFINITION = null;
+
+ public GregtechMTE_NuclearReactor(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMTE_NuclearReactor(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public long maxEUStore() {
+ return (640000000L * (Math.min(16, this.mEnergyHatches.size()))) / 16L;
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Reactor";
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return GTPPRecipeMaps.liquidFluorineThoriumReactorRecipes;
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Liquid Fluoride Thorium Reactor.")
+ .addInfo("Produces energy and new elements from Radioactive Beta Decay!")
+ .addInfo("Input LFTB and a molten salt as fuel, and match the 4 Buffered Dynamo Hatches:")
+ .addInfo("LFTR Fuel 1 (4 EV Hatches), LFTR Fuel 2 (4 IV Hatches), LFTR Fuel 3 (4 LuV Hatches)")
+ .addInfo("If using better hatches for a worse fuel, only 1 hatch will output EU")
+ .addInfo("Outputs U233 every 10 seconds, on average, while the reactor is running")
+ .addInfo("Check NEI to see the other 3 outputs - they differ between fuels")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(7, 4, 7, true)
+ .addController("Bottom Center")
+ .addCasingInfoMin("Hastelloy-N Reactor Casing", 27, false)
+ .addCasingInfoMin("Zeron-100 Reactor Shielding", 26, false)
+ .addInputHatch("Top or bottom layer edges", 1)
+ .addOutputHatch("Top or bottom layer edges", 1)
+ .addDynamoHatch("Top or bottom layer edges", 1)
+ .addMaintenanceHatch("Top or bottom layer edges", 1)
+ .addMufflerHatch("Top 3x3", 2)
+ .addStructureInfo("All dynamos must be between EV and LuV tier.")
+ .addStructureInfo("All other hatches must be IV+ tier.")
+ .addStructureInfo("4x Output Hatches or 1x Output Hatch (ME), 1+ Input Hatches, 4x Dynamo Hatches")
+ .addStructureInfo("2x Maintenance Hatches, 4x Mufflers")
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public String[] getExtraInfoData() {
+ final String tRunning = (this.mMaxProgresstime > 0 ? "Reactor running" : "Reactor stopped");
+ final String tMaintainance = (this.getIdealStatus() == this.getRepairStatus() ? "No Maintainance issues"
+ : "Needs Maintainance");
+
+ return new String[] { "Liquid Fluoride Thorium Reactor", tRunning, tMaintainance,
+ "Current Output: " + this.lEUt + " EU/t", "Fuel Remaining: " + this.mFuelRemaining + " Litres",
+ "Current Efficiency: " + (this.mEfficiency / 5) + "%", "Current Efficiency (Raw): " + (this.mEfficiency),
+ "It requires you to have 100% Efficiency." };
+ }
+
+ @Override
+ public boolean allowCoverOnSide(final ForgeDirection side, final GT_ItemStack aStack) {
+ return side != this.getBaseMetaTileEntity()
+ .getFrontFacing();
+ }
+
+ @Override
+ public ITexture[] getTexture(final IGregTechTileEntity aBaseMetaTileEntity, final ForgeDirection side,
+ final ForgeDirection facing, final int aColorIndex, final boolean aActive, final boolean aRedstone) {
+ boolean aWarmedUp = this.mEfficiency == this.getMaxEfficiency(null);
+ if (!aBaseMetaTileEntity.isActive() || !aWarmedUp) {
+ if (side == facing) {
+ if (aActive) return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(TAE.GTPP_INDEX(12)),
+ TextureFactory.builder()
+ .addIcon(Textures.BlockIcons.OVERLAY_FRONT_REPLICATOR_ACTIVE)
+ .extFacing()
+ .build() };
+ return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(TAE.GTPP_INDEX(12)),
+ TextureFactory.builder()
+ .addIcon(Textures.BlockIcons.OVERLAY_FRONT_REPLICATOR)
+ .extFacing()
+ .build() };
+ }
+ return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(TAE.GTPP_INDEX(12)) };
+ } else if (aBaseMetaTileEntity.isActive() && aWarmedUp) {
+ if (side == facing) {
+ if (aActive) return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(TAE.GTPP_INDEX(13)),
+ TextureFactory.builder()
+ .addIcon(Textures.BlockIcons.OVERLAY_FRONT_REPLICATOR_ACTIVE)
+ .extFacing()
+ .build() };
+ return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(TAE.GTPP_INDEX(13)),
+ TextureFactory.builder()
+ .addIcon(Textures.BlockIcons.OVERLAY_FRONT_REPLICATOR)
+ .extFacing()
+ .build() };
+ }
+ return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(TAE.GTPP_INDEX(13)) };
+ }
+ return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(TAE.GTPP_INDEX(12)) };
+ }
+
+ public final boolean addNuclearReactorEdgeList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) {
+ if (aTileEntity == null) {
+ return false;
+ } else {
+ IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+ if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Maintenance) {
+ return addToMachineList(aTileEntity, aBaseCasingIndex);
+ } else if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Dynamo dynamo
+ && dynamo.getTierForStructure() >= 4
+ && dynamo.getTierForStructure() <= 6) {
+ return addToMachineList(aTileEntity, aBaseCasingIndex);
+ } else if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Input hatch
+ && hatch.getTierForStructure() >= 5) {
+ return addToMachineList(aTileEntity, aBaseCasingIndex);
+ } else if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Output hatch
+ && hatch.getTierForStructure() >= 5) {
+ return addToMachineList(aTileEntity, aBaseCasingIndex);
+ }
+ }
+ return false;
+ }
+
+ public final boolean addNuclearReactorTopList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) {
+ if (aTileEntity == null) {
+ return false;
+ } else {
+ IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+ if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Muffler hatch && hatch.getTierForStructure() >= 5) {
+ return addToMachineList(aTileEntity, aBaseCasingIndex);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMTE_NuclearReactor> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMTE_NuclearReactor>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] {
+ { "CCCCCCC", "COOOOOC", "COXXXOC", "COXXXOC", "COXXXOC", "COOOOOC", "CCCCCCC" },
+ { "GGGGGGG", "G-----G", "G-----G", "G-----G", "G-----G", "G-----G", "GGGGGGG" },
+ { "GGGGGGG", "G-----G", "G-----G", "G-----G", "G-----G", "G-----G", "GGGGGGG" },
+ { "CCC~CCC", "COOOOOC", "COOOOOC", "COOOOOC", "COOOOOC", "COOOOOC", "CCCCCCC" }, }))
+ .addElement(
+ 'C',
+ ofChain(
+ buildHatchAdder(GregtechMTE_NuclearReactor.class).atLeast(Maintenance)
+ .casingIndex(TAE.GTPP_INDEX(12))
+ .dot(1)
+ .build(),
+ buildHatchAdder(GregtechMTE_NuclearReactor.class).atLeast(InputHatch, OutputHatch)
+ .adder(GregtechMTE_NuclearReactor::addNuclearReactorEdgeList)
+ .hatchItemFilterAnd(t -> filterByMTETier(5, Integer.MAX_VALUE))
+ .casingIndex(TAE.GTPP_INDEX(12))
+ .dot(1)
+ .build(),
+ buildHatchAdder(GregtechMTE_NuclearReactor.class).atLeast(Dynamo)
+ .adder(GregtechMTE_NuclearReactor::addNuclearReactorEdgeList)
+ .hatchItemFilterAnd(t -> filterByMTETier(4, 6))
+ .casingIndex(TAE.GTPP_INDEX(12))
+ .dot(1)
+ .build(),
+ onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasingsMisc, 12))))
+ .addElement(
+ 'X',
+ buildHatchAdder(GregtechMTE_NuclearReactor.class).atLeast(Muffler)
+ .adder(GregtechMTE_NuclearReactor::addNuclearReactorTopList)
+ .hatchItemFilterAnd(t -> filterByMTETier(5, Integer.MAX_VALUE))
+ .casingIndex(TAE.GTPP_INDEX(12))
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasingsMisc, 12))))
+ .addElement('O', ofBlock(ModBlocks.blockCasingsMisc, 12))
+ .addElement('G', ofBlock(ModBlocks.blockCasingsMisc, 13))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 3, 3, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 3, 3, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ if (checkPiece(mName, 3, 3, 0) && mCasing >= 27) {
+ if ((mOutputHatches.size() >= 3 || canDumpFluidToME()) && mInputHatches.size() >= 1
+ && mDynamoHatches.size() == 4
+ && mMufflerHatches.size() == 4
+ && mMaintenanceHatches.size() == 2) {
+ fixAllMaintenanceIssue();
+ this.turnCasingActive(false);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Alk's Life Lessons from Greg.
+ /*
+ * [23:41:15] <GregoriusTechneticies> xdir and zdir are x2 and not x3 [23:41:26] <GregoriusTechneticies> thats you
+ * issue [23:44:33] <Alkalus> mmm? [23:44:49] <Alkalus> Should they be x3? [23:44:50] <GregoriusTechneticies> you
+ * just do a x2, what is for a 5x5 multiblock [23:45:01] <GregoriusTechneticies> x3 is for a 7x7 one [23:45:06]
+ * <Alkalus> I have no idea what that value does, tbh.. [23:45:15] <GregoriusTechneticies> its the offset [23:45:23]
+ * <Alkalus> Debugging checkMachine has been a pain and I usually trash designs that don't work straight up..
+ * [23:45:28] <GregoriusTechneticies> it determines the horizontal middle of the multiblock [23:45:47]
+ * <GregoriusTechneticies> which is in your case THREE blocks away from the controller [23:45:51] <Alkalus> Ahh
+ * [23:45:57] <GregoriusTechneticies> and not 2 [23:46:06] <Alkalus> Noted, thanks :D
+ */
+
+ @Override
+ public boolean isCorrectMachinePart(final ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerTick(final ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public int getDamageToComponent(final ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMTE_NuclearReactor(this.mName);
+ }
+
+ public boolean turnCasingActive(final boolean status) {
+ // TODO
+ if (this.mDynamoHatches != null) {
+ for (final GT_MetaTileEntity_Hatch_Dynamo hatch : this.mDynamoHatches) {
+ hatch.updateTexture(status ? TAE.GTPP_INDEX(13) : TAE.GTPP_INDEX(12));
+ }
+ }
+ if (this.mMufflerHatches != null) {
+ for (final GT_MetaTileEntity_Hatch_Muffler hatch : this.mMufflerHatches) {
+ hatch.updateTexture(status ? TAE.GTPP_INDEX(13) : TAE.GTPP_INDEX(12));
+ }
+ }
+ if (this.mOutputHatches != null) {
+ for (final GT_MetaTileEntity_Hatch_Output hatch : this.mOutputHatches) {
+ hatch.updateTexture(status ? TAE.GTPP_INDEX(13) : TAE.GTPP_INDEX(12));
+ }
+ }
+ if (this.mInputHatches != null) {
+ for (final GT_MetaTileEntity_Hatch_Input hatch : this.mInputHatches) {
+ hatch.updateTexture(status ? TAE.GTPP_INDEX(13) : TAE.GTPP_INDEX(12));
+ }
+ }
+ if (this.mMaintenanceHatches != null) {
+ for (final GT_MetaTileEntity_Hatch_Maintenance hatch : this.mMaintenanceHatches) {
+ hatch.updateTexture(status ? TAE.GTPP_INDEX(13) : TAE.GTPP_INDEX(12));
+ }
+ }
+ return true;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic() {
+
+ @NotNull
+ @Override
+ protected GT_OverclockCalculator createOverclockCalculator(@NotNull GT_Recipe recipe) {
+ return GT_OverclockCalculator.ofNoOverclock(recipe.mSpecialValue * 4L, recipe.mDuration);
+ }
+
+ @NotNull
+ @Override
+ public CheckRecipeResult process() {
+ CheckRecipeResult result = super.process();
+ if (!result.wasSuccessful()) {
+ resetMultiProcessing();
+ }
+ return result;
+ }
+
+ @NotNull
+ @Override
+ protected CheckRecipeResult validateRecipe(@NotNull GT_Recipe recipe) {
+ mFuelRemaining = 0;
+ int li2bef4 = 0;
+ FluidStack aFuelFluid = null;
+ for (FluidStack aFluidInput : recipe.mFluidInputs) {
+ if (!aFluidInput.getFluid()
+ .equals(NUCLIDE.Li2BeF4.getFluid())) {
+ aFuelFluid = aFluidInput;
+ break;
+ }
+ }
+ if (aFuelFluid != null) {
+ for (FluidStack fluidStack : getStoredFluids()) {
+ if (fluidStack.isFluidEqual(aFuelFluid)) {
+ mFuelRemaining += fluidStack.amount;
+ } else if (fluidStack.getFluid()
+ .equals(NUCLIDE.Li2BeF4.getFluid())) {
+ li2bef4 += fluidStack.amount;
+ }
+ }
+ }
+ if (mFuelRemaining < 100) {
+ return CheckRecipeResultRegistry.NO_FUEL_FOUND;
+ }
+ if (li2bef4 < 200) {
+ return SimpleCheckRecipeResult.ofFailure("no_li2bef4");
+ }
+ return CheckRecipeResultRegistry.SUCCESSFUL;
+ }
+ };
+ }
+
+ protected void resetMultiProcessing() {
+ this.mEfficiency = 0;
+ this.mLastRecipe = null;
+ stopMachine(ShutDownReasonRegistry.NONE);
+ }
+
+ @Override
+ public @NotNull CheckRecipeResult checkProcessing() {
+ // Warm up for 4~ minutes
+ if (mEfficiency < this.getMaxEfficiency(null)) {
+ this.mMaxProgresstime = 1;
+ this.mEfficiencyIncrease = 2;
+ return SimpleCheckRecipeResult.ofSuccess("warm_up");
+ }
+ CheckRecipeResult result = super.checkProcessing();
+ if (result.wasSuccessful()) {
+ // We produce EU, so we negate the value, if negative
+ if (lEUt < 0) {
+ lEUt = -lEUt;
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 1;
+ }
+
+ @Override
+ public void explodeMultiblock() {
+ this.mInventory[1] = null;
+ long explodevalue = MathUtils.randLong(Integer.MAX_VALUE, 8589934588L);
+ for (final MetaTileEntity tTileEntity : this.mInputBusses) {
+ explodevalue = MathUtils.randLong(Integer.MAX_VALUE, 8589934588L);
+ tTileEntity.getBaseMetaTileEntity()
+ .doExplosion(explodevalue);
+ }
+ for (final MetaTileEntity tTileEntity : this.mOutputBusses) {
+ explodevalue = MathUtils.randLong(Integer.MAX_VALUE, 8589934588L);
+ tTileEntity.getBaseMetaTileEntity()
+ .doExplosion(explodevalue);
+ }
+ for (final MetaTileEntity tTileEntity : this.mInputHatches) {
+ explodevalue = MathUtils.randLong(Integer.MAX_VALUE, 8589934588L);
+ tTileEntity.getBaseMetaTileEntity()
+ .doExplosion(explodevalue);
+ }
+ for (final MetaTileEntity tTileEntity : this.mOutputHatches) {
+ explodevalue = MathUtils.randLong(Integer.MAX_VALUE, 8589934588L);
+ tTileEntity.getBaseMetaTileEntity()
+ .doExplosion(explodevalue);
+ }
+ for (final MetaTileEntity tTileEntity : this.mDynamoHatches) {
+ explodevalue = MathUtils.randLong(Integer.MAX_VALUE, 8589934588L);
+ tTileEntity.getBaseMetaTileEntity()
+ .doExplosion(explodevalue);
+ }
+ for (final MetaTileEntity tTileEntity : this.mMufflerHatches) {
+ explodevalue = MathUtils.randLong(Integer.MAX_VALUE, 8589934588L);
+ tTileEntity.getBaseMetaTileEntity()
+ .doExplosion(explodevalue);
+ }
+ for (final MetaTileEntity tTileEntity : this.mEnergyHatches) {
+ explodevalue = MathUtils.randLong(Integer.MAX_VALUE, 8589934588L);
+ tTileEntity.getBaseMetaTileEntity()
+ .doExplosion(explodevalue);
+ }
+ for (final MetaTileEntity tTileEntity : this.mMaintenanceHatches) {
+ explodevalue = MathUtils.randLong(Integer.MAX_VALUE, 8589934588L);
+ tTileEntity.getBaseMetaTileEntity()
+ .doExplosion(explodevalue);
+ }
+ explodevalue = MathUtils.randLong(Integer.MAX_VALUE, 8589934588L);
+ this.getBaseMetaTileEntity()
+ .doExplosion(explodevalue);
+ }
+
+ @Override
+ public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {
+ if (aBaseMetaTileEntity.getWorld().isRemote) {
+ if (aBaseMetaTileEntity.isActive()) {
+ // Set casings active if we're warmed up.
+ if (this.mEfficiency == this.getMaxEfficiency(null)) {
+ this.turnCasingActive(true);
+ } else {
+ this.turnCasingActive(false);
+ }
+ } else {
+ this.turnCasingActive(false);
+ }
+ }
+ super.onPostTick(aBaseMetaTileEntity, aTick);
+ }
+
+ @Override
+ public boolean onRunningTick(ItemStack aStack) {
+ // See if we're warmed up.
+ if (this.mEfficiency == this.getMaxEfficiency(null)) {
+ // Try output some Uranium-233
+ if (MathUtils.randInt(1, 300) == 1) {
+ this.addOutput(ELEMENT.getInstance().URANIUM233.getFluidStack(MathUtils.randInt(1, 10)));
+ }
+ }
+ return super.onRunningTick(aStack);
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ aNBT.setInteger("mFuelRemaining", this.mFuelRemaining);
+ super.saveNBTData(aNBT);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ this.mFuelRemaining = aNBT.getInteger("mFuelRemaining");
+ super.loadNBTData(aNBT);
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntityTreeFarm.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntityTreeFarm.java
new file mode 100644
index 0000000000..0441907f40
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntityTreeFarm.java
@@ -0,0 +1,809 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+import static gregtech.api.util.GT_Utility.filterValidMTEs;
+import static gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase.GTPPHatchElement.TTEnergy;
+
+import java.util.ArrayList;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import net.minecraft.init.Items;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemShears;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraftforge.fluids.FluidStack;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import forestry.api.arboriculture.IToolGrafter;
+import forestry.api.arboriculture.ITree;
+import forestry.api.arboriculture.TreeManager;
+import gregtech.api.enums.GT_Values;
+import gregtech.api.enums.Mods;
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.items.GT_MetaGenerated_Tool;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_InputBus;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.recipe.check.SimpleCheckRecipeResult;
+import gregtech.api.util.GT_ModHandler;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.GT_Utility;
+import gregtech.api.util.VoidProtectionHelper;
+import gregtech.common.items.GT_MetaGenerated_Tool_01;
+import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_InputBus_ME;
+import gtPlusPlus.api.objects.Logger;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.minecraft.ItemUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+import gtPlusPlus.xmod.gregtech.common.items.MetaGeneratedGregtechTools;
+
+public class GregtechMetaTileEntityTreeFarm extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntityTreeFarm>
+ implements ISurvivalConstructable {
+
+ public static int CASING_TEXTURE_ID;
+ private static final int TICKS_PER_OPERATION = 100;
+ private static final int TOOL_DAMAGE_PER_OPERATION = 1;
+ private static final int TOOL_CHARGE_PER_OPERATION = 32;
+
+ private int mCasing;
+ public static String mCasingName = "Sterile Farm Casing";
+ private static IStructureDefinition<GregtechMetaTileEntityTreeFarm> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntityTreeFarm(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ CASING_TEXTURE_ID = TAE.getIndexFromPage(1, 15);
+ }
+
+ public GregtechMetaTileEntityTreeFarm(final String aName) {
+ super(aName);
+ CASING_TEXTURE_ID = TAE.getIndexFromPage(1, 15);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntityTreeFarm(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Tree Farm";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller block for the Tree Growth Simulator")
+ .addInfo("Farms and harvests trees using EU")
+ .addInfo("Place a sapling in the controller slot")
+ .addInfo("Place a tool in an input bus")
+ .addInfo("Different tools are required for different outputs")
+ .addInfo("Advanced tools multiply output amount")
+ .addInfo(" Logs: Saw (1x), Buzzsaw (2x), Chainsaw (4x)")
+ .addInfo(" Saplings: Branch Cutter (1x), Grafter (3x)")
+ .addInfo(" Leaves: Shears (1x), Wire Cutter (2x), Automatic Snips (4x)")
+ .addInfo(" Fruit: Knife (1x)")
+ .addInfo("Multiple tools can be used at the same time")
+ .addSeparator()
+ .addInfo("Work time is fixed at 5 seconds")
+ .addInfo("Energy input tier multiplies output further")
+ .addInfo("Output multiplier is equal to: 2*tier^2 - 2*tier + 5")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 3, 3, true)
+ .addController("Front center")
+ .addCasingInfoMin(mCasingName, 8, false)
+ .addInputBus("Any casing", 1)
+ .addStructureInfo(
+ EnumChatFormatting.YELLOW + "Stocking Input Busses and Crafting Input Busses/Buffers are not allowed!")
+ .addOutputBus("Any casing", 1)
+ .addEnergyHatch("Any casing", 1)
+ .addMaintenanceHatch("Any casing", 1)
+ .addMufflerHatch("Any casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return CASING_TEXTURE_ID;
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ return checkPiece(mName, 1, 1, 0) && mCasing >= 8 && checkHatch();
+ }
+
+ @Override
+ public boolean addInputBusToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) {
+ // Tools from a stocking inout bus can not be damaged, this would cause an infinite durability exploit.
+ // Therefore disallow ME input bus.
+ if (aTileEntity == null) return false;
+ IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+ if (aMetaTileEntity == null) return false;
+ if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_InputBus_ME) return false;
+ return super.addInputBusToMachineList(aTileEntity, aBaseCasingIndex);
+ }
+
+ @Override
+ public boolean supportsCraftingMEBuffer() {
+ return false;
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 1;
+ }
+
+ @Override
+ public boolean supportsBatchMode() {
+ // Batch mode would not do anything, processing time is fixed at 100 ticks.
+ return false;
+ }
+
+ @Override
+ public boolean isBatchModeEnabled() {
+ return false;
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiTreeFarm;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntityTreeFarm> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntityTreeFarm>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC" }, { "C~C", "C-C", "CCC" }, { "CCC", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntityTreeFarm.class)
+ .atLeast(
+ InputHatch,
+ OutputHatch,
+ InputBus,
+ OutputBus,
+ Maintenance,
+ Energy.or(TTEnergy),
+ Muffler)
+ .casingIndex(CASING_TEXTURE_ID)
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings2Misc, 15))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 1, 0, elementBudget, env, false, true);
+ }
+
+ /* Processing logic. */
+
+ @Override
+ public boolean isCorrectMachinePart(final ItemStack aStack) {
+ if (aStack == null) return false;
+ if (isValidSapling(aStack)) return true;
+ /*
+ * In previous versions, a saw used to go in the controller slot. We do not want an update to stop processing of
+ * a machine set up like this. Instead, a sapling is placed in this slot at the start of the next operation.
+ */
+ if (aStack.getItem() instanceof GT_MetaGenerated_Tool_01) return true;
+ return false;
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ // Only for NEI, not used in processing logic.
+ return GTPPRecipeMaps.treeGrowthSimulatorFakeRecipes;
+ }
+
+ /**
+ * Valid processing modes (types of output) for the Tree Growth Simulator.
+ */
+ public enum Mode {
+ LOG,
+ SAPLING,
+ LEAVES,
+ FRUIT
+ }
+
+ /**
+ * Edit this to change relative yields for different modes. For example, logs are output at 5 times the rate of
+ * saplings.
+ */
+ private static final EnumMap<Mode, Integer> modeMultiplier = new EnumMap<>(Mode.class);
+ static {
+ modeMultiplier.put(Mode.LOG, 5);
+ modeMultiplier.put(Mode.SAPLING, 1);
+ modeMultiplier.put(Mode.LEAVES, 2);
+ modeMultiplier.put(Mode.FRUIT, 1);
+ }
+
+ /**
+ * Return the output multiplier for a given power tier.
+ *
+ * @param tier Power tier the machine runs on.
+ * @return Factor to multiply all outputs by.
+ */
+ private static int getTierMultiplier(int tier) {
+ /*
+ * Where does this formula come from? [12:57 AM] boubou_19: i did. Basically Pandoro measured the output of a
+ * WA-ed farming station for each tier of WA, then i computed the Lagrange interpolating polynomial of his
+ * dataset, which gave this
+ */
+ return (2 * (tier * tier)) - (2 * tier) + 5;
+ }
+
+ /**
+ * Key of this map is the registry name of the sapling, followed by ":", and the sapling's metadata value.
+ * <p>
+ * The value of the map is a list of products by {@link Mode}. Products for some modes can be null if the tree does
+ * not produce anything in that mode (for example, it has no fruit).
+ */
+ public static final HashMap<String, EnumMap<Mode, ItemStack>> treeProductsMap = new HashMap<>();
+
+ @Override
+ public ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic() {
+
+ @Override
+ @Nonnull
+ public CheckRecipeResult process() {
+ if (inputItems == null) {
+ inputItems = new ItemStack[0];
+ }
+ if (inputFluids == null) {
+ inputFluids = new FluidStack[0];
+ }
+
+ ItemStack sapling = findSapling();
+ if (sapling == null) return SimpleCheckRecipeResult.ofFailure("no_sapling");
+
+ EnumMap<Mode, ItemStack> outputPerMode = getOutputsForSapling(sapling);
+ if (outputPerMode == null) {
+ // This should usually not be possible, outputs for all valid saplings should be defined.
+ Logger.INFO("No output found for sapling: " + sapling.getDisplayName());
+ return SimpleCheckRecipeResult.ofFailure("no_output_for_sapling");
+ }
+
+ int tier = Math.max(1, GT_Utility.getTier(availableVoltage * availableAmperage));
+ int tierMultiplier = getTierMultiplier(tier);
+
+ List<ItemStack> outputs = new ArrayList<>();
+ for (Mode mode : Mode.values()) {
+ ItemStack output = outputPerMode.get(mode);
+ if (output == null) continue; // This sapling has no output in this mode.
+
+ // Find a tool to use in this mode.
+ int toolMultiplier = useToolForMode(mode);
+ if (toolMultiplier < 0) continue; // No valid tool for this mode found.
+
+ // Increase output by the relevant multipliers.
+ ItemStack out = output.copy();
+ out.stackSize *= tierMultiplier * modeMultiplier.get(mode) * toolMultiplier;
+ outputs.add(out);
+ }
+
+ if (outputs.isEmpty()) {
+ // No outputs can be produced using the tools we have available.
+ return SimpleCheckRecipeResult.ofFailure("no_tools");
+ }
+
+ outputItems = outputs.toArray(new ItemStack[0]);
+
+ VoidProtectionHelper voidProtection = new VoidProtectionHelper().setMachine(machine)
+ .setItemOutputs(outputItems)
+ .build();
+ if (voidProtection.isItemFull()) {
+ return CheckRecipeResultRegistry.ITEM_OUTPUT_FULL;
+ }
+
+ duration = TICKS_PER_OPERATION;
+ calculatedEut = GT_Values.VP[tier];
+
+ return SimpleCheckRecipeResult.ofSuccess("growing_trees");
+ }
+ };
+ }
+
+ /* Handling tools. */
+
+ /**
+ * Attempts to find a tool appropriate for the given mode, and damage/discharge it by one use.
+ *
+ * @param mode The mode to use. This specifies which tools are valid.
+ * @return Production multiplier based on the tool used, or -1 if no appropriate tool was found.
+ */
+ private int useToolForMode(Mode mode) {
+ for (ItemStack stack : getStoredInputs()) {
+ int toolMultiplier = getToolMultiplier(stack, mode);
+ if (toolMultiplier < 0) continue;
+ boolean canDamage = GT_ModHandler
+ .damageOrDechargeItem(stack, TOOL_DAMAGE_PER_OPERATION, TOOL_CHARGE_PER_OPERATION, null);
+ if (canDamage) {
+ // Tool was used.
+ if (GT_ModHandler.isElectricItem(stack)
+ && !GT_ModHandler.canUseElectricItem(stack, TOOL_CHARGE_PER_OPERATION)) {
+ // Tool is out of charge, move it to output.
+ depleteInput(stack);
+ addOutput(stack);
+ }
+ return toolMultiplier;
+ } else {
+ // Correct item type, but the tool could not be used.
+ depleteInput(stack);
+ addOutput(stack);
+ }
+
+ }
+ return -1;
+ }
+
+ /**
+ * Calculate output multiplier for a given tool and mode.
+ *
+ * @param toolStack The tool to use.
+ * @param mode The mode to use.
+ * @return Output multiplier for the given tool used in the given mode. If the tool is not appropriate for this
+ * mode, returns -1.
+ */
+ public static int getToolMultiplier(ItemStack toolStack, Mode mode) {
+ Item tool = toolStack.getItem();
+ switch (mode) {
+ case LOG:
+ if (tool instanceof GT_MetaGenerated_Tool_01) {
+ switch (toolStack.getItemDamage()) {
+ case GT_MetaGenerated_Tool_01.SAW:
+ case GT_MetaGenerated_Tool_01.POCKET_SAW:
+ case GT_MetaGenerated_Tool_01.POCKET_MULTITOOL:
+ return 1;
+ case GT_MetaGenerated_Tool_01.BUZZSAW_LV:
+ case GT_MetaGenerated_Tool_01.BUZZSAW_MV:
+ case GT_MetaGenerated_Tool_01.BUZZSAW_HV:
+ return 2;
+ case GT_MetaGenerated_Tool_01.CHAINSAW_LV:
+ case GT_MetaGenerated_Tool_01.CHAINSAW_MV:
+ case GT_MetaGenerated_Tool_01.CHAINSAW_HV:
+ return 4;
+ }
+ }
+ break;
+
+ case SAPLING:
+ if (tool instanceof GT_MetaGenerated_Tool_01) {
+ switch (toolStack.getItemDamage()) {
+ case GT_MetaGenerated_Tool_01.BRANCHCUTTER:
+ case GT_MetaGenerated_Tool_01.POCKET_BRANCHCUTTER:
+ case GT_MetaGenerated_Tool_01.POCKET_MULTITOOL:
+ return 1;
+ }
+ }
+ if (tool instanceof IToolGrafter && tool.isDamageable()) {
+ return 3;
+ }
+ break;
+
+ case LEAVES:
+ // Do not allow unbreakable tools. Operation should have a running cost.
+ if (tool instanceof ItemShears && tool.isDamageable()) {
+ return 1;
+ }
+ if (tool instanceof GT_MetaGenerated_Tool_01) {
+ switch (toolStack.getItemDamage()) {
+ case GT_MetaGenerated_Tool_01.POCKET_MULTITOOL:
+ return 1;
+ case GT_MetaGenerated_Tool_01.WIRECUTTER:
+ case GT_MetaGenerated_Tool_01.POCKET_WIRECUTTER:
+ return 2;
+ }
+ }
+ if (tool instanceof MetaGeneratedGregtechTools) {
+ if (toolStack.getItemDamage() == MetaGeneratedGregtechTools.ELECTRIC_SNIPS) {
+ return 4;
+ }
+ }
+ break;
+
+ case FRUIT:
+ if (tool instanceof GT_MetaGenerated_Tool_01) {
+ switch (toolStack.getItemDamage()) {
+ case GT_MetaGenerated_Tool_01.KNIFE:
+ case GT_MetaGenerated_Tool_01.POCKET_KNIFE:
+ case GT_MetaGenerated_Tool_01.POCKET_MULTITOOL:
+ return 1;
+ }
+ }
+ break;
+ }
+
+ // No valid tool was found.
+ return -1;
+ }
+
+ /* Handling saplings. */
+
+ /**
+ * Finds a valid sapling from input buses, and places it into the controller slot.
+ *
+ * @return The sapling that was found (now in the controller slot).
+ */
+ private ItemStack findSapling() {
+ ItemStack controllerSlot = getControllerSlot();
+
+ if (isValidSapling(controllerSlot)) {
+ return controllerSlot;
+ }
+
+ if (controllerSlot != null) {
+ // Non-sapling item in controller slot. This could be a saw from an older version of the TGS.
+ // We first try to swap it with a sapling from an input bus to not interrupt existing setups.
+ if (!legacyToolSwap()) {
+ // Swap failed, output whatever is blocking the slot.
+ addOutput(controllerSlot);
+ mInventory[1] = null;
+ }
+ }
+
+ // Here controller slot is empty, find a valid sapling to use.
+ for (ItemStack stack : getStoredInputs()) {
+ if (isValidSapling(stack)) {
+ mInventory[1] = stack.splitStack(1);
+ return mInventory[1];
+ }
+ }
+
+ // No saplings were found.
+ return null;
+ }
+
+ /**
+ * In previous versions, the saw used to be placed in the controller slot and the sapling into an input bus. We do
+ * not want to break existing setups like this, so we attempt to swap the two if possible.
+ *
+ * @return True on success, false otherwise.
+ */
+ private boolean legacyToolSwap() {
+ ItemStack controllerSlot = getControllerSlot();
+ if (controllerSlot == null || !(controllerSlot.getItem() instanceof GT_MetaGenerated_Tool_01)) return false;
+
+ for (GT_MetaTileEntity_Hatch_InputBus inputBus : filterValidMTEs(mInputBusses)) {
+ ItemStack[] inventory = inputBus.getRealInventory();
+ for (int slot = 0; slot < inventory.length; ++slot) {
+ if (isValidSapling(inventory[slot])) {
+ // Do the swap.
+ mInventory[1] = inventory[slot];
+ inventory[slot] = controllerSlot;
+ inputBus.updateSlots();
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if an ItemStack is a sapling that can be farmed.
+ *
+ * @param stack An ItemStack.
+ * @return True if stack is a valid sapling that can be farmed.
+ */
+ private boolean isValidSapling(ItemStack stack) {
+ if (stack == null) return false;
+ String registryName = Item.itemRegistry.getNameForObject(stack.getItem());
+ return treeProductsMap.containsKey(registryName + ":" + stack.getItemDamage())
+ || "Forestry:sapling".equals(registryName);
+ }
+
+ /**
+ * Get a list of possible outputs for a sapling, for each mode. This is either recovered from
+ * {@link #treeProductsMap}, or generated from stats of Forestry saplings.
+ *
+ * @param sapling A sapling to farm.
+ * @return A map of outputs for each mode. Outputs for some modes might be null.
+ */
+ private static EnumMap<Mode, ItemStack> getOutputsForSapling(ItemStack sapling) {
+ String registryName = Item.itemRegistry.getNameForObject(sapling.getItem());
+ if ("Forestry:sapling".equals(registryName)) {
+ return getOutputsForForestrySapling(sapling);
+ } else {
+ return treeProductsMap.get(registryName + ":" + sapling.getItemDamage());
+ }
+ }
+
+ /**
+ * Calculate outputs for Forestry saplings. Default amounts stored in {@link #treeProductsMap} are adjusted based
+ * the genetics of the input sapling.
+ * <p>
+ * Relevant stats:
+ * <ul>
+ * <li>height, girth: Affects log output.</li>
+ * <li>fertility (called Saplings in game): Affects sapling output.</li>
+ * <li>yield: Affects fruit output.</li>
+ * </ul>
+ * See {@link forestry.core.genetics.alleles.EnumAllele} for detailed numeric values for each allele.
+ *
+ * @param sapling A sapling to farm. Must be a Forestry sapling with a valid genome.
+ * @return A map of outputs for each mode. Outputs for some modes might be null.
+ */
+ private static EnumMap<Mode, ItemStack> getOutputsForForestrySapling(ItemStack sapling) {
+ ITree tree = TreeManager.treeRoot.getMember(sapling);
+ if (tree == null) return null;
+
+ String speciesUUID = tree.getIdent();
+
+ EnumMap<Mode, ItemStack> defaultMap = treeProductsMap.get("Forestry:sapling:" + speciesUUID);
+ if (defaultMap == null) return null;
+
+ // We need to make a new map so that we don't modify the stored amounts of outputs.
+ EnumMap<Mode, ItemStack> adjustedMap = new EnumMap<>(Mode.class);
+
+ ItemStack log = defaultMap.get(Mode.LOG);
+ if (log != null) {
+ double height = Math.max(
+ 3 * (tree.getGenome()
+ .getHeight() - 1),
+ 0) + 1;
+ double girth = tree.getGenome()
+ .getGirth();
+
+ log = log.copy();
+ log.stackSize = (int) (log.stackSize * height * girth);
+ adjustedMap.put(Mode.LOG, log);
+ }
+
+ ItemStack saplingOut = defaultMap.get(Mode.SAPLING);
+ if (saplingOut != null) {
+ // Lowest = 0.01 ... Average = 0.05 ... Highest = 0.3
+ double fertility = tree.getGenome()
+ .getFertility() * 10;
+
+ // Return a copy of the *input* sapling, retaining its genetics.
+ int stackSize = Math.max(1, (int) (saplingOut.stackSize * fertility));
+ saplingOut = sapling.copy();
+ saplingOut.stackSize = stackSize;
+ adjustedMap.put(Mode.SAPLING, saplingOut);
+ }
+
+ ItemStack leaves = defaultMap.get(Mode.LEAVES);
+ if (leaves != null) {
+ adjustedMap.put(Mode.LEAVES, leaves.copy());
+ }
+
+ ItemStack fruit = defaultMap.get(Mode.FRUIT);
+ if (fruit != null) {
+ // Lowest = 0.025 ... Average = 0.2 ... Highest = 0.4
+ double yield = tree.getGenome()
+ .getYield() * 10;
+
+ fruit = fruit.copy();
+ fruit.stackSize = (int) (fruit.stackSize * yield);
+ adjustedMap.put(Mode.FRUIT, fruit);
+ }
+
+ return adjustedMap;
+ }
+
+ /* Recipe registration. */
+
+ /**
+ * Registers outputs for a sapling. This method assumes that output in mode SAPLING is the same as the input
+ * sapling. Output amount is further modified by mode, machine tier, and tool used. Recipes are added in
+ * {@link gtPlusPlus.xmod.gregtech.loaders.recipe.RecipeLoader_TreeFarm}.
+ *
+ * @param sapling The input sapling to farm, and also the output in mode SAPLING.
+ * @param log ItemStack to output in mode LOG.
+ * @param leaves ItemStack to output in mode LEAVES.
+ * @param fruit ItemStack to output in mode FRUIT.
+ */
+ public static void registerTreeProducts(ItemStack sapling, ItemStack log, ItemStack leaves, ItemStack fruit) {
+ registerTreeProducts(sapling, log, sapling, leaves, fruit);
+ }
+
+ /**
+ * Registers outputs for a sapling. Output amount is further modified by mode, machine tier, and tool used. Recipes
+ * are added in {@link gtPlusPlus.xmod.gregtech.loaders.recipe.RecipeLoader_TreeFarm}.
+ *
+ * @param saplingIn The input sapling to farm.
+ * @param log ItemStack to output in mode LOG.
+ * @param saplingOut ItemStack to output in mode SAPLING.
+ * @param leaves ItemStack to output in mode LEAVES.
+ * @param fruit ItemStack to output in mode FRUIT.
+ */
+ public static void registerTreeProducts(ItemStack saplingIn, ItemStack log, ItemStack saplingOut, ItemStack leaves,
+ ItemStack fruit) {
+ String key = Item.itemRegistry.getNameForObject(saplingIn.getItem()) + ":" + saplingIn.getItemDamage();
+ EnumMap<Mode, ItemStack> map = new EnumMap<>(Mode.class);
+ if (log != null) map.put(Mode.LOG, log);
+ if (saplingOut != null) map.put(Mode.SAPLING, saplingOut);
+ if (leaves != null) map.put(Mode.LEAVES, leaves);
+ if (fruit != null) map.put(Mode.FRUIT, fruit);
+ treeProductsMap.put(key, map);
+
+ if (!addFakeRecipeToNEI(saplingIn, log, saplingOut, leaves, fruit)) {
+ Logger.INFO("Registering NEI fake recipe for " + key + " failed!");
+ }
+ }
+
+ /**
+ * For Forestry trees, the output amounts depend on the genetics of the sapling. Here we register only the types of
+ * items to output. In {@link #getOutputsForForestrySapling(ItemStack)} these outputs are then multiplied according
+ * to the stats of the real sapling that is in the controller slot.
+ */
+ public static void registerForestryTree(String speciesUID, ItemStack sapling, ItemStack log, ItemStack leaves,
+ ItemStack fruit) {
+ String key = "Forestry:sapling:" + speciesUID;
+ EnumMap<Mode, ItemStack> map = new EnumMap<>(Mode.class);
+ map.put(Mode.LOG, log);
+ map.put(Mode.SAPLING, sapling);
+ map.put(Mode.LEAVES, leaves);
+ map.put(Mode.FRUIT, fruit);
+ treeProductsMap.put(key, map);
+
+ // In the NEI recipe we want to display outputs adjusted for the default genetics of this tree type.
+ // To do this we use the same method as when calculating real outputs.
+ map = getOutputsForForestrySapling(sapling);
+ if (map == null) {
+ Logger.INFO("Could not create Forestry tree output map for " + speciesUID);
+ return;
+ }
+ addFakeRecipeToNEI(
+ sapling,
+ map.get(Mode.LOG),
+ map.get(Mode.SAPLING),
+ map.get(Mode.LEAVES),
+ map.get(Mode.FRUIT));
+ }
+
+ /**
+ * This array is used to get the rotating display of items in NEI showing all possible tools for a given mode.
+ */
+ private static final ItemStack[][] altToolsForNEI;
+ static {
+ GT_MetaGenerated_Tool toolInstance = GT_MetaGenerated_Tool_01.INSTANCE;
+ altToolsForNEI = new ItemStack[][] {
+ // Mode.LOG
+ { toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.SAW, 1, null, null, null),
+ toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.POCKET_SAW, 1, null, null, null),
+ toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.BUZZSAW_LV, 1, null, null, null),
+ toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.CHAINSAW_LV, 1, null, null, null),
+ toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.BUZZSAW_MV, 1, null, null, null),
+ toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.CHAINSAW_MV, 1, null, null, null),
+ toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.BUZZSAW_HV, 1, null, null, null),
+ toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.CHAINSAW_HV, 1, null, null, null), },
+ // Mode.SAPLING
+ { toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.BRANCHCUTTER, 1, null, null, null),
+ toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.POCKET_BRANCHCUTTER, 1, null, null, null),
+ GT_ModHandler.getModItem(Mods.Forestry.ID, "grafter", 1, 0), },
+ // Mode.LEAVES
+ { new ItemStack(Items.shears),
+ toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.WIRECUTTER, 1, null, null, null),
+ toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.POCKET_WIRECUTTER, 1, null, null, null),
+ MetaGeneratedGregtechTools.getInstance()
+ .getToolWithStats(MetaGeneratedGregtechTools.ELECTRIC_SNIPS, 1, null, null, null), },
+ // Mode.FRUIT
+ { toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.KNIFE, 1, null, null, null),
+ toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.POCKET_KNIFE, 1, null, null, null), } };
+ }
+
+ /**
+ * Add a recipe for this tree to NEI. These recipes are only used in NEI, they are never used for processing logic.
+ *
+ * @return True if the recipe was added successfully.
+ */
+ public static boolean addFakeRecipeToNEI(ItemStack saplingIn, ItemStack log, ItemStack saplingOut, ItemStack leaves,
+ ItemStack fruit) {
+ int recipeCount = GTPPRecipeMaps.treeGrowthSimulatorFakeRecipes.getAllRecipes()
+ .size();
+
+ // Sapling goes into the "special" slot.
+ ItemStack specialStack = saplingIn.copy();
+ specialStack.stackSize = 0;
+
+ /*
+ * Calculate the correct amount of outputs for each mode. The amount displayed in NEI should take into account
+ * the mode multiplier, but not tool/tier multipliers as those can change dynamically. If the sapling has an
+ * output in this mode, also add the tools usable for this mode as inputs.
+ */
+ ItemStack[][] inputStacks = new ItemStack[Mode.values().length][];
+ ItemStack[] outputStacks = new ItemStack[Mode.values().length];
+
+ for (Mode mode : Mode.values()) {
+ ItemStack output = switch (mode) {
+ case LOG -> log;
+ case SAPLING -> saplingOut;
+ case LEAVES -> leaves;
+ case FRUIT -> fruit;
+ };
+ if (output != null) {
+ int ordinal = mode.ordinal();
+ inputStacks[ordinal] = altToolsForNEI[ordinal];
+ outputStacks[ordinal] = output.copy();
+ outputStacks[ordinal].stackSize *= modeMultiplier.get(mode);
+ }
+ }
+
+ Logger.INFO(
+ "Adding Tree Growth Simulation NEI recipe for " + specialStack.getDisplayName()
+ + " -> "
+ + ItemUtils.getArrayStackNames(outputStacks));
+
+ GTPPRecipeMaps.treeGrowthSimulatorFakeRecipes.addFakeRecipe(
+ false,
+ new GT_Recipe.GT_Recipe_WithAlt(
+ false,
+ null, // All inputs are taken from aAtl argument.
+ outputStacks,
+ specialStack,
+ null,
+ null,
+ null,
+ TICKS_PER_OPERATION,
+ 0,
+ recipeCount, // special value, also sorts recipes correctly in order of addition.
+ inputStacks));
+
+ return GTPPRecipeMaps.treeGrowthSimulatorFakeRecipes.getAllRecipes()
+ .size() > recipeCount;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_AlloyBlastSmelter.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_AlloyBlastSmelter.java
new file mode 100644
index 0000000000..580efdcdab
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_AlloyBlastSmelter.java
@@ -0,0 +1,235 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.StatCollector;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.SoundResource;
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.api.objects.Logger;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.recipe.common.CI;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_AlloyBlastSmelter
+ extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_AlloyBlastSmelter> implements ISurvivalConstructable {
+
+ private int mMode = 0;
+ private boolean isUsingControllerCircuit = false;
+ private static Item circuit;
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_AlloyBlastSmelter> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_AlloyBlastSmelter(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_AlloyBlastSmelter(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_AlloyBlastSmelter(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Fluid Alloy Cooker";
+ }
+
+ @Override
+ public void loadNBTData(final NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ if (aNBT.hasKey("isBussesSeparate")) {
+ inputSeparation = aNBT.getBoolean("isBussesSeparate");
+ }
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Alloy Blast Smelter")
+ .addInfo("20% Faster than the Electric Blast Furnace")
+ .addInfo("Allows Complex GT++ alloys to be created")
+ .addInfo("Accepts only one Energy Hatch")
+ .addInfo("Circuit for recipe goes in the Input Bus or GUI slot")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 4, 3, true)
+ .addController("Bottom Center")
+ .addCasingInfoMin("Blast Smelter Casings", 5, false)
+ .addCasingInfoMin("Blast Smelter Heat Containment Coils", 16, false)
+ .addInputBus("Any Casing", 1)
+ .addInputHatch("Any Casing", 1)
+ .addOutputHatch("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_AlloyBlastSmelter> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_AlloyBlastSmelter>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC" }, { "HHH", "H-H", "HHH" }, { "HHH", "H-H", "HHH" },
+ { "C~C", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntity_AlloyBlastSmelter.class)
+ .atLeast(InputBus, InputHatch, OutputBus, OutputHatch, Maintenance, Energy, Muffler)
+ .casingIndex(TAE.GTPP_INDEX(15))
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasingsMisc, 15))))
+ .addElement('H', ofBlock(ModBlocks.blockCasingsMisc, 14))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 3, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 3, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ return checkPiece(mName, 1, 3, 0) && mCasing >= 5 && mEnergyHatches.size() == 1 && checkHatch();
+ }
+
+ @Override
+ protected SoundResource getProcessStartSound() {
+ return SoundResource.IC2_MACHINES_INDUCTION_LOOP;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return TAE.GTPP_INDEX(15);
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return GTPPRecipeMaps.alloyBlastSmelterRecipes;
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(final ItemStack aStack) {
+ if (this.getBaseMetaTileEntity()
+ .isServerSide()) {
+ // Get Controller Circuit
+ if (circuit == null) {
+ circuit = CI.getNumberedCircuit(0)
+ .getItem();
+ }
+ if (aStack != null && aStack.getItem() == circuit) {
+ this.mMode = aStack.getItemDamage();
+ return this.isUsingControllerCircuit = true;
+ } else {
+ if (aStack == null) {
+ this.isUsingControllerCircuit = false;
+ return true; // Allowed empty
+ }
+ Logger.WARNING("Not circuit in GUI inputs.");
+ return this.isUsingControllerCircuit = false;
+ }
+ }
+ Logger.WARNING("No Circuit, clientside.");
+ return this.isUsingControllerCircuit = false;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic();
+ }
+
+ @Override
+ public void onModeChangeByScrewdriver(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+ inputSeparation = !inputSeparation;
+ GT_Utility.sendChatToPlayer(
+ aPlayer,
+ StatCollector.translateToLocal("GT5U.machines.separatebus") + " " + inputSeparation);
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 1;
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiABS;
+ }
+
+ @Override
+ public int getDamageToComponent(final ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public boolean supportsInputSeparation() {
+ return true;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_Cyclotron.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_Cyclotron.java
new file mode 100644
index 0000000000..5861885bd0
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_Cyclotron.java
@@ -0,0 +1,331 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import net.minecraft.block.Block;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.SoundResource;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.metatileentity.MetaTileEntity;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_OutputBus;
+import gregtech.api.objects.GT_ItemStack;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.item.chemistry.IonParticles;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.math.MathUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_Cyclotron extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_Cyclotron>
+ implements ISurvivalConstructable {
+
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_Cyclotron> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_Cyclotron(int aID, String aName, String aNameRegional, int tier) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_Cyclotron(String aName) {
+ super(aName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Particle Accelerator";
+ }
+
+ public int tier() {
+ return 5;
+ }
+
+ @Override
+ public long maxEUStore() {
+ return 1800000000L;
+ }
+
+ @Override
+ public MetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_Cyclotron(this.mName);
+ }
+
+ @Override
+ public boolean allowCoverOnSide(ForgeDirection side, GT_ItemStack aStack) {
+ return side != getBaseMetaTileEntity().getFrontFacing();
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ super.saveNBTData(aNBT);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_Cyclotron> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_Cyclotron>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] {
+ { " ", " hhh ", " hh hh ", " h h ",
+ " h h ", " h h ", " h h ", " h h ",
+ " h h ", " h h ", " h h ", " h h ",
+ " hh hh ", " hhh ", " ", },
+ { " hhh ", " hhccchh ", " hcchhhcch ", " hchh hhch ",
+ " hch hch ", " hch hch ", "hch hch", "hch hch",
+ "hch hch", " hch hch ", " hch hch ", " hchh hhch ",
+ " hcch~hcch ", " hhccchh ", " hhh ", },
+ { " ", " hhh ", " hh hh ", " h h ",
+ " h h ", " h h ", " h h ", " h h ",
+ " h h ", " h h ", " h h ", " h h ",
+ " hh hh ", " hhh ", " ", } }))
+ .addElement(
+ 'h',
+ buildHatchAdder(GregtechMetaTileEntity_Cyclotron.class)
+ .atLeast(InputBus, OutputBus, Maintenance, Energy, Muffler, InputHatch, OutputHatch)
+ .casingIndex(44)
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(getCasingBlock(), getCasingMeta()))))
+ .addElement('c', ofBlock(getCyclotronCoil(), getCyclotronCoilMeta()))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 7, 1, 12);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 7, 1, 12, elementBudget, env, false, true);
+ }
+
+ @Override
+ protected SoundResource getProcessStartSound() {
+ return SoundResource.GT_MACHINES_FUSION_LOOP;
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ return checkPiece(mName, 7, 1, 12) && mCasing >= 40 && checkHatch();
+ }
+
+ public Block getCasingBlock() {
+ return ModBlocks.blockCasings2Misc;
+ }
+
+ public int getCasingMeta() {
+ return 10;
+ }
+
+ public Block getCyclotronCoil() {
+ return ModBlocks.blockCasings2Misc;
+ }
+
+ public int getCyclotronCoilMeta() {
+ return 9;
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Super Magnetic Speed Shooter")
+ .addSeparator()
+ .addInfo("Particles are accelerated over 186 revolutions to 80% light speed")
+ .addInfo("Can produce a continuous beam current of 2.2 mA at 590 MeV")
+ .addInfo("Which will be extracted from the Isochronous Cyclotron")
+ .addSeparator()
+ .addInfo("Consists of the same layout as a Fusion Reactor")
+ .addInfo("Any external casing can be a hatch/bus, unlike Fusion")
+ .addInfo("Cyclotron Machine Casings around Cyclotron Coil Blocks")
+ .addInfo("All Hatches must be IV or better")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .addCasingInfoMin("Cyclotron Machine Casings", 40, false)
+ .addCasingInfoMin("Cyclotron Coil", 32, false)
+ .addInputBus("Any Casing", 1)
+ .addOutputBus("Any Casing", 1)
+ .addInputHatch("Any Casing", 1)
+ .addOutputHatch("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return getIconOverlay();
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return getIconOverlay();
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return 44;
+ }
+
+ public IIconContainer getIconOverlay() {
+ if (this.getBaseMetaTileEntity()
+ .isActive()) {
+ return TexturesGtBlock.Overlay_MatterFab_Active_Animated;
+ }
+ return TexturesGtBlock.Overlay_MatterFab_Animated;
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return GTPPRecipeMaps.cyclotronRecipes;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic() {
+
+ @NotNull
+ @Override
+ public CheckRecipeResult process() {
+ fixAllMaintenanceIssue();
+ CheckRecipeResult result = super.process();
+ if (result.wasSuccessful()) {
+ for (ItemStack s : outputItems) {
+ if (s != null) {
+ if (s.getItem() instanceof IonParticles) {
+ long aCharge = IonParticles.getChargeState(s);
+ if (aCharge == 0) {
+ IonParticles.setChargeState(
+ s,
+ MathUtils.getRandomFromArray(
+ new int[] { -5, -5, -4, -4, -4, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -2,
+ -2, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
+ 5, 5, 5, 6, 6 }));
+ }
+ }
+ }
+ }
+ }
+ return result;
+ }
+ };
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 1;
+ }
+
+ @Override
+ public boolean onRunningTick(ItemStack aStack) {
+ if (this.mOutputBusses.size() > 0) {
+ for (GT_MetaTileEntity_Hatch_OutputBus g : this.mOutputBusses) {
+ if (g != null) {
+ for (ItemStack s : g.mInventory) {
+ if (s != null) {
+ if (s.getItem() instanceof IonParticles) {
+ long aCharge = IonParticles.getChargeState(s);
+ if (aCharge == 0) {
+ IonParticles.setChargeState(
+ s,
+ MathUtils.getRandomFromArray(
+ new int[] { -5, -5, -4, -4, -4, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -2,
+ -2, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
+ 5, 5, 5, 6, 6 }));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ this.fixAllMaintenanceIssue();
+ return super.onRunningTick(aStack);
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiCyclotron;
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public String[] getExtraInfoData() {
+ String tier = tier() == 5 ? "I" : "II";
+ float plasmaOut = 0;
+ int powerRequired = 0;
+ if (this.mLastRecipe != null) {
+ powerRequired = this.mLastRecipe.mEUt;
+ if (this.mLastRecipe.getFluidOutput(0) != null) {
+ plasmaOut = (float) this.mLastRecipe.getFluidOutput(0).amount / (float) this.mLastRecipe.mDuration;
+ }
+ }
+
+ return new String[] { "COMET - Compact Cyclotron MK " + tier, "EU Required: " + powerRequired + "EU/t",
+ "Stored EU: " + this.getEUVar() + " / " + maxEUStore() };
+ }
+
+ @Override
+ public boolean doesBindPlayerInventory() {
+ return false;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_IndustrialFishingPond.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_IndustrialFishingPond.java
new file mode 100644
index 0000000000..78e4a17274
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_IndustrialFishingPond.java
@@ -0,0 +1,489 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+import static gtPlusPlus.core.util.data.ArrayUtils.removeNulls;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import net.minecraft.block.Block;
+import net.minecraft.init.Blocks;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.WeightedRandomFishable;
+import net.minecraftforge.fluids.FluidStack;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits;
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.TAE;
+import gregtech.api.enums.Textures;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.recipe.check.SimpleCheckRecipeResult;
+import gregtech.api.util.FishPondFakeRecipe;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_OverclockCalculator;
+import gregtech.api.util.GT_ParallelHelper;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.api.objects.data.AutoMap;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.recipe.common.CI;
+import gtPlusPlus.core.util.math.MathUtils;
+import gtPlusPlus.core.util.minecraft.FluidUtils;
+import gtPlusPlus.core.util.minecraft.ItemUtils;
+import gtPlusPlus.core.util.reflect.ReflectionUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import ic2.core.init.BlocksItems;
+import ic2.core.init.InternalName;
+
+public class GregtechMetaTileEntity_IndustrialFishingPond extends
+ GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialFishingPond> implements ISurvivalConstructable {
+
+ private boolean isUsingControllerCircuit = false;
+ private static final Item circuit = CI.getNumberedCircuit(0)
+ .getItem();
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialFishingPond> STRUCTURE_DEFINITION = null;
+ private static final Class<?> cofhWater;
+
+ static {
+ cofhWater = ReflectionUtils.getClass("cofh.asmhooks.block.BlockWater");
+ }
+
+ public GregtechMetaTileEntity_IndustrialFishingPond(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_IndustrialFishingPond(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IndustrialFishingPond(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Fish Trap";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Fishing Pond")
+ .addInfo("Can process (Tier + 1) * 2 recipes")
+ .addInfo("Put a numbered circuit into the input bus.")
+ .addInfo("Circuit 14 for Fish")
+ .addInfo("Circuit 15 for Junk")
+ .addInfo("Circuit 16 for Treasure")
+ .addInfo("Need to be filled with water.")
+ .addInfo("Will automatically fill water from input hatch.")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(9, 3, 9, true)
+ .addController("Front Center")
+ .addCasingInfoMin("Aquatic Casings", 64, false)
+ .addInputBus("Any Casing", 1)
+ .addOutputBus("Any Casing", 1)
+ .addInputHatch("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ protected IAlignmentLimits getInitialAlignmentLimits() {
+ return (d, r, f) -> d.offsetY == 0 && r.isNotRotated() && !f.isVerticallyFliped();
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialFishingPond> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialFishingPond>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] {
+ { "XXXXXXXXX", "X X", "X X", "X X", "X X", "X X", "X X",
+ "X X", "XXXXXXXXX" },
+ { "XXXX~XXXX", "X X", "X X", "X X", "X X", "X X", "X X",
+ "X X", "XXXXXXXXX" },
+ { "XXXXXXXXX", "XXXXXXXXX", "XXXXXXXXX", "XXXXXXXXX", "XXXXXXXXX", "XXXXXXXXX", "XXXXXXXXX",
+ "XXXXXXXXX", "XXXXXXXXX" }, }))
+ .addElement(
+ 'X',
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialFishingPond.class)
+ .atLeast(InputBus, OutputBus, Maintenance, Energy, Muffler, InputHatch)
+ .casingIndex(getCasingTextureIndex())
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(getCasingBlock(), getCasingMeta()))))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 4, 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 4, 1, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ return checkPiece(mName, 4, 1, 0) && mCasing >= 64 && checkHatch();
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return Textures.BlockIcons.OVERLAY_FRONT_VACUUM_FREEZER_ACTIVE;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return Textures.BlockIcons.OVERLAY_FRONT_VACUUM_FREEZER;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return getCasingTextureIndex();
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return GTPPRecipeMaps.fishPondRecipes;
+ }
+
+ @Override
+ protected boolean filtersFluid() {
+ return false;
+ }
+
+ @Override
+ public @NotNull CheckRecipeResult checkProcessing() {
+ ItemStack controllerStack = getControllerSlot();
+ if (controllerStack != null) {
+ if (controllerStack.getItem() == circuit) {
+ this.isUsingControllerCircuit = true;
+ this.mMode = controllerStack.getItemDamage();
+ } else {
+ this.isUsingControllerCircuit = false;
+ }
+ } else {
+ this.isUsingControllerCircuit = false;
+ }
+ if (!hasGenerateRecipes) {
+ generateRecipes();
+ }
+ if (!checkForWater()) {
+ return SimpleCheckRecipeResult.ofFailure("no_water");
+ }
+ ItemStack[] tItemInputs = getStoredInputs().toArray(new ItemStack[0]);
+ FluidStack[] tFluidInputs = getStoredFluids().toArray(new FluidStack[0]);
+
+ if (!isUsingControllerCircuit && tItemInputs.length == 0) {
+ return CheckRecipeResultRegistry.NO_RECIPE;
+ }
+
+ long tEnergy = getMaxInputEnergy();
+
+ getCircuit(tItemInputs);
+
+ ItemStack[] mFishOutput = generateLoot(this.mMode);
+ mFishOutput = removeNulls(mFishOutput);
+ GT_Recipe g = new GT_Recipe(
+ true,
+ new ItemStack[] {},
+ mFishOutput,
+ null,
+ new int[] {},
+ tFluidInputs,
+ null,
+ 200,
+ 16,
+ 0);
+ GT_OverclockCalculator calculator = new GT_OverclockCalculator().setRecipeEUt(g.mEUt)
+ .setEUt(tEnergy)
+ .setDuration(g.mDuration);
+ GT_ParallelHelper helper = new GT_ParallelHelper().setRecipe(g)
+ .setItemInputs(tItemInputs)
+ .setFluidInputs(tFluidInputs)
+ .setAvailableEUt(tEnergy)
+ .setMaxParallel(getMaxParallelRecipes())
+ .setConsumption(true)
+ .setOutputCalculation(true)
+ .setMachine(this)
+ .enableBatchMode(batchMode ? 128 : 1)
+ .setCalculator(calculator);
+
+ helper.build();
+
+ if (helper.getCurrentParallel() == 0) {
+ return CheckRecipeResultRegistry.ITEM_OUTPUT_FULL;
+ }
+
+ this.mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000);
+ this.mEfficiencyIncrease = 10000;
+
+ lEUt = -calculator.getConsumption();
+ mMaxProgresstime = (int) Math.ceil(calculator.getDuration() * helper.getDurationMultiplierDouble());
+
+ mOutputItems = helper.getItemOutputs();
+ mOutputFluids = null;
+ updateSlots();
+
+ return CheckRecipeResultRegistry.SUCCESSFUL;
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return (2 * (GT_Utility.getTier(this.getMaxInputVoltage()) + 1));
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialFishingPond;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ public Block getCasingBlock() {
+ return ModBlocks.blockCasings3Misc;
+ }
+
+ public byte getCasingMeta() {
+ return 0;
+ }
+
+ public int getCasingTextureIndex() {
+ return TAE.GTPP_INDEX(32);
+ }
+
+ public boolean checkForWater() {
+
+ // Get Facing direction
+ IGregTechTileEntity aBaseMetaTileEntity = this.getBaseMetaTileEntity();
+ int mDirectionX = aBaseMetaTileEntity.getBackFacing().offsetX;
+ int mCurrentDirectionX;
+ int mCurrentDirectionZ;
+ int mOffsetX_Lower = 0;
+ int mOffsetX_Upper = 0;
+ int mOffsetZ_Lower = 0;
+ int mOffsetZ_Upper = 0;
+
+ mCurrentDirectionX = 4;
+ mCurrentDirectionZ = 4;
+
+ mOffsetX_Lower = -4;
+ mOffsetX_Upper = 4;
+ mOffsetZ_Lower = -4;
+ mOffsetZ_Upper = 4;
+
+ // if (aBaseMetaTileEntity.fac)
+
+ final int xDir = aBaseMetaTileEntity.getBackFacing().offsetX * mCurrentDirectionX;
+ final int zDir = aBaseMetaTileEntity.getBackFacing().offsetZ * mCurrentDirectionZ;
+
+ int tAmount = 0;
+ for (int i = mOffsetX_Lower + 1; i <= mOffsetX_Upper - 1; ++i) {
+ for (int j = mOffsetZ_Lower + 1; j <= mOffsetZ_Upper - 1; ++j) {
+ for (int h = 0; h < 2; h++) {
+ Block tBlock = aBaseMetaTileEntity.getBlockOffset(xDir + i, h, zDir + j);
+ byte tMeta = aBaseMetaTileEntity.getMetaIDOffset(xDir + i, h, zDir + j);
+ if (isNotStaticWater(tBlock, tMeta)) {
+ if (this.getStoredFluids() != null) {
+ for (FluidStack stored : this.getStoredFluids()) {
+ if (stored.isFluidEqual(FluidUtils.getFluidStack("water", 1))) {
+ if (stored.amount >= 1000) {
+ // Utils.LOG_WARNING("Going to try swap an air block for water from inut bus.");
+ stored.amount -= 1000;
+ Block fluidUsed = Blocks.water;
+ aBaseMetaTileEntity.getWorld()
+ .setBlock(
+ aBaseMetaTileEntity.getXCoord() + xDir + i,
+ aBaseMetaTileEntity.getYCoord() + h,
+ aBaseMetaTileEntity.getZCoord() + zDir + j,
+ fluidUsed);
+ }
+ }
+ }
+ }
+ }
+ tBlock = aBaseMetaTileEntity.getBlockOffset(xDir + i, h, zDir + j);
+ if (tBlock == Blocks.water || tBlock == Blocks.flowing_water) {
+ ++tAmount;
+ }
+ }
+ }
+ }
+
+ return tAmount >= 60;
+ }
+
+ private boolean isNotStaticWater(Block block, byte meta) {
+ return block == Blocks.air || block == Blocks.flowing_water
+ || block == BlocksItems.getFluidBlock(InternalName.fluidDistilledWater)
+ || (cofhWater != null && cofhWater.isAssignableFrom(block.getClass()) && meta != 0);
+ }
+
+ private static AutoMap<AutoMap<WeightedRandomFishable>> categories = new AutoMap<>();
+ private static AutoMap<WeightedRandomFishable> categoryFish = new AutoMap<>();
+ private static AutoMap<WeightedRandomFishable> categoryJunk = new AutoMap<>();
+ private static AutoMap<WeightedRandomFishable> categoryLoot = new AutoMap<>();
+ private static boolean hasGenerateRecipes = false;
+ private int mMode = 14;
+ private int mMax = 8;
+
+ private void generateRecipes() {
+ if (hasGenerateRecipes) return;
+
+ categories.put(categoryFish);
+ categories.put(categoryJunk);
+ categories.put(categoryLoot);
+ for (WeightedRandomFishable h : FishPondFakeRecipe.fish) {
+ categoryFish.put(h);
+ }
+ for (WeightedRandomFishable h : FishPondFakeRecipe.junk) {
+ categoryJunk.put(h);
+ }
+ for (WeightedRandomFishable h : FishPondFakeRecipe.treasure) {
+ categoryLoot.put(h);
+ }
+ hasGenerateRecipes = true;
+ }
+
+ private int getCircuit(ItemStack[] t) {
+ if (!this.isUsingControllerCircuit) {
+ for (ItemStack j : t) {
+ if (j.getItem() == CI.getNumberedCircuit(0)
+ .getItem()) {
+ // Fish
+ if (j.getItemDamage() == 14) {
+ mMax = 8 + (this.getMaxParallelRecipes() - 2);
+ this.mMode = 14;
+ break;
+ }
+ // Junk
+ else if (j.getItemDamage() == 15) {
+ this.mMode = 15;
+ mMax = 4;
+ break;
+ }
+ // Loot
+ else if (j.getItemDamage() == 16) {
+ this.mMode = 16;
+ mMax = 4;
+ break;
+ } else {
+ this.mMode = 0;
+ mMax = 0;
+ break;
+ }
+ } else {
+ this.mMode = 0;
+ mMax = 0;
+ break;
+ }
+ }
+ }
+ return this.mMode;
+ }
+
+ // reflection map
+ private static Map<WeightedRandomFishable, ItemStack> reflectiveFishMap = new HashMap<>();
+
+ private ItemStack reflectiveFish(WeightedRandomFishable y) {
+ if (reflectiveFishMap.containsKey(y)) {
+ return reflectiveFishMap.get(y);
+ }
+ ItemStack t;
+ try {
+ t = (ItemStack) ReflectionUtils.getField(WeightedRandomFishable.class, "field_150711_b")
+ .get(y);
+ ItemStack k = ItemUtils.getSimpleStack(t, 1);
+ reflectiveFishMap.put(y, k);
+ return t;
+ } catch (IllegalArgumentException | IllegalAccessException e) {}
+ return null;
+ }
+
+ private ItemStack[] generateLoot(int mode) {
+ ItemStack[] mFishOutput = new ItemStack[this.mMax];
+ if (this.mMode == 14) {
+ for (int k = 0; k < this.mMax; k++) {
+ if (mFishOutput[k] == null) for (WeightedRandomFishable g : categoryFish.values()) {
+ if (MathUtils.randInt(0, (65 - getMaxParallelRecipes())) <= 2) {
+ ItemStack t = reflectiveFish(g);
+ if (t != null) {
+ mFishOutput[k] = ItemUtils.getSimpleStack(t, 1);
+ }
+ }
+ }
+ }
+ } else if (this.mMode == 15) {
+ for (int k = 0; k < this.mMax; k++) {
+ if (mFishOutput[k] == null) for (WeightedRandomFishable g : categoryJunk.values()) {
+ if (MathUtils.randInt(0, 100) <= 1) {
+ ItemStack t = reflectiveFish(g);
+ if (t != null) {
+ mFishOutput[k] = ItemUtils.getSimpleStack(t, 1);
+ }
+ }
+ }
+ }
+ } else if (this.mMode == 16) {
+ for (int k = 0; k < this.mMax; k++) {
+ if (mFishOutput[k] == null) for (WeightedRandomFishable g : categoryLoot.values()) {
+ if (MathUtils.randInt(0, 1000) <= 2) {
+ ItemStack t = reflectiveFish(g);
+ if (t != null) {
+ mFishOutput[k] = ItemUtils.getSimpleStack(t, 1);
+ }
+ }
+ }
+ }
+ } else {
+ mFishOutput = null;
+ }
+ return mFishOutput;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_IndustrialRockBreaker.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_IndustrialRockBreaker.java
new file mode 100644
index 0000000000..e7e74ac061
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_IndustrialRockBreaker.java
@@ -0,0 +1,367 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import java.util.ArrayList;
+
+import net.minecraft.init.Blocks;
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.fluids.FluidRegistry;
+import net.minecraftforge.fluids.FluidStack;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.Materials;
+import gregtech.api.enums.OrePrefixes;
+import gregtech.api.enums.SoundResource;
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.recipe.check.SimpleCheckRecipeResult;
+import gregtech.api.util.GT_LanguageManager;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_OreDictUnificator;
+import gregtech.api.util.GT_OverclockCalculator;
+import gregtech.api.util.GT_ParallelHelper;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.recipe.common.CI;
+import gtPlusPlus.core.util.minecraft.ItemUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_IndustrialRockBreaker extends
+ GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_IndustrialRockBreaker> implements ISurvivalConstructable {
+
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_IndustrialRockBreaker> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_IndustrialRockBreaker(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_IndustrialRockBreaker(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_IndustrialRockBreaker(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Rock Breaker";
+ }
+
+ private static final String casingBaseName = GT_LanguageManager.getTranslation("gtplusplus.blockcasings.2.0.name");
+ private static final String casingMiddleName = GT_LanguageManager
+ .getTranslation("gtplusplus.blockcasings.2.11.name");
+ private static final String anyBaseCasing = "Any " + casingBaseName;
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Industrial Rock Breaker")
+ .addInfo("Speed: +200% | EU Usage: 75% | Parallel: Tier x 8")
+ .addInfo("Circuit goes in the GUI slot")
+ .addInfo("1 = cobble, 2 = stone, 3 = obsidian")
+ .addInfo("Supply Water/Lava")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 4, 3, true)
+ .addController("Bottom Center")
+ .addCasingInfoMin(casingBaseName, 9, false)
+ .addCasingInfoExactly(casingMiddleName, 16, false)
+ .addInputBus(anyBaseCasing, 1)
+ .addInputHatch(anyBaseCasing, 1)
+ .addOutputBus(anyBaseCasing, 1)
+ .addEnergyHatch(anyBaseCasing, 1)
+ .addMaintenanceHatch(anyBaseCasing, 1)
+ .addMufflerHatch(anyBaseCasing, 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_IndustrialRockBreaker> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_IndustrialRockBreaker>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCC", "CCC", "CCC" }, { "HHH", "H-H", "HHH" }, { "HHH", "H-H", "HHH" },
+ { "C~C", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntity_IndustrialRockBreaker.class)
+ .atLeast(InputBus, InputHatch, OutputBus, Maintenance, Energy, Muffler)
+ .casingIndex(TAE.GTPP_INDEX(16))
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings2Misc, 0))))
+ .addElement('H', ofBlock(ModBlocks.blockCasings2Misc, 11))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 3, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 3, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ boolean aCheckPiece = checkPiece(mName, 1, 3, 0);
+ boolean aCasingCount = mCasing >= 9;
+ boolean aCheckHatch = checkHatch();
+ log("" + aCheckPiece + ", " + aCasingCount + ", " + aCheckHatch);
+ return aCheckPiece && aCasingCount && aCheckHatch;
+ }
+
+ @Override
+ protected SoundResource getProcessStartSound() {
+ return SoundResource.IC2_MACHINES_INDUCTION_LOOP;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return TAE.GTPP_INDEX(16);
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return RecipeMaps.rockBreakerFakeRecipes;
+ }
+
+ @Override
+ protected boolean filtersFluid() {
+ return false;
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(final ItemStack aStack) {
+ return true;
+ }
+
+ private static GT_Recipe sRecipe_Cobblestone;
+ private static GT_Recipe sRecipe_SmoothStone;
+ private static GT_Recipe sRecipe_Redstone;
+
+ private static void generateRecipes() {
+ sRecipe_Cobblestone = new GT_Recipe(
+ false,
+ new ItemStack[] { CI.getNumberedCircuit(1) },
+ new ItemStack[] { ItemUtils.getSimpleStack(Blocks.cobblestone) },
+ null,
+ new int[] { 10000 },
+ null,
+ null,
+ 16,
+ 32,
+ 0);
+ sRecipe_SmoothStone = new GT_Recipe(
+ false,
+ new ItemStack[] { CI.getNumberedCircuit(2) },
+ new ItemStack[] { ItemUtils.getSimpleStack(Blocks.stone) },
+ null,
+ new int[] { 10000 },
+ null,
+ null,
+ 16,
+ 32,
+ 0);
+ sRecipe_Redstone = new GT_Recipe(
+ false,
+ new ItemStack[] { CI.getNumberedCircuit(3),
+ GT_OreDictUnificator.get(OrePrefixes.dust, Materials.Redstone, 1L) },
+ new ItemStack[] { ItemUtils.getSimpleStack(Blocks.obsidian) },
+ null,
+ new int[] { 10000 },
+ null,
+ null,
+ 128,
+ 32,
+ 0);
+ }
+
+ @Override
+ public @NotNull CheckRecipeResult checkProcessing() {
+ ArrayList<FluidStack> aFluids = this.getStoredFluids();
+ if (aFluids.isEmpty()) {
+ return CheckRecipeResultRegistry.NO_RECIPE;
+ }
+
+ boolean aHasWater = false;
+ boolean aHasLava = false;
+ for (FluidStack aFluid : aFluids) {
+ if (aFluid.getFluid() == FluidRegistry.WATER) {
+ aHasWater = true;
+ } else if (aFluid.getFluid() == FluidRegistry.LAVA) {
+ aHasLava = true;
+ }
+ }
+ ArrayList<ItemStack> aItems = this.getStoredInputs();
+ boolean aHasRedstone = false;
+ if (!aItems.isEmpty()) {
+ for (ItemStack aItem : aItems) {
+ if (GT_Utility
+ .areStacksEqual(aItem, GT_OreDictUnificator.get(OrePrefixes.dust, Materials.Redstone, 1L))) {
+ aHasRedstone = true;
+ break;
+ }
+ }
+ }
+
+ if (!aHasWater) {
+ return SimpleCheckRecipeResult.ofFailure("no_water");
+ }
+ if (!aHasLava) {
+ return SimpleCheckRecipeResult.ofFailure("no_lava");
+ }
+ ItemStack aGuiCircuit = this.getControllerSlot();
+ if (!ItemUtils.isControlCircuit(aGuiCircuit)) {
+ return CheckRecipeResultRegistry.NO_RECIPE;
+ }
+
+ if (sRecipe_Cobblestone == null || sRecipe_SmoothStone == null || sRecipe_Redstone == null) {
+ generateRecipes();
+ }
+
+ int aCircuit = aGuiCircuit.getItemDamage();
+
+ GT_Recipe tRecipe = null;
+ switch (aCircuit) {
+ case 1 -> tRecipe = sRecipe_Cobblestone;
+ case 2 -> tRecipe = sRecipe_SmoothStone;
+ case 3 -> {
+ if (aHasRedstone) {
+ tRecipe = sRecipe_Redstone;
+ }
+ }
+ }
+
+ if (tRecipe == null) {
+ return CheckRecipeResultRegistry.NO_RECIPE;
+ }
+
+ ItemStack[] aItemInputs = aItems.toArray(new ItemStack[0]);
+ FluidStack[] aFluidInputs = new FluidStack[] {};
+
+ long tEnergy = getMaxInputEnergy();
+ // Remember last recipe - an optimization for findRecipe()
+ this.mLastRecipe = tRecipe;
+
+ GT_ParallelHelper helper = new GT_ParallelHelper().setRecipe(tRecipe)
+ .setItemInputs(aItemInputs)
+ .setFluidInputs(aFluidInputs)
+ .setAvailableEUt(tEnergy)
+ .setMaxParallel(getMaxParallelRecipes())
+ .setConsumption(true)
+ .setOutputCalculation(true)
+ .setEUtModifier(0.75F)
+ .setMachine(this);
+
+ if (batchMode) {
+ helper.enableBatchMode(128);
+ }
+
+ helper.build();
+
+ if (helper.getCurrentParallel() == 0) {
+ return CheckRecipeResultRegistry.ITEM_OUTPUT_FULL;
+ }
+
+ this.mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000);
+ this.mEfficiencyIncrease = 10000;
+
+ GT_OverclockCalculator calculator = new GT_OverclockCalculator().setRecipeEUt(tRecipe.mEUt)
+ .setEUt(tEnergy)
+ .setDuration(tRecipe.mDuration)
+ .setEUtDiscount(0.75F)
+ .setSpeedBoost(1F / 3F)
+ .setParallel((int) Math.floor(helper.getCurrentParallel() / helper.getDurationMultiplierDouble()))
+ .calculate();
+ lEUt = -calculator.getConsumption();
+ mMaxProgresstime = (int) Math.ceil(calculator.getDuration() * helper.getDurationMultiplierDouble());
+
+ mOutputItems = helper.getItemOutputs();
+ mOutputFluids = helper.getFluidOutputs();
+ updateSlots();
+ return CheckRecipeResultRegistry.SUCCESSFUL;
+
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return (8 * GT_Utility.getTier(this.getMaxInputVoltage()));
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiIndustrialRockBreaker;
+ }
+
+ @Override
+ public int getDamageToComponent(final ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public ArrayList<ItemStack> getStoredInputs() {
+ ArrayList<ItemStack> aInputs = super.getStoredInputs();
+ if (this.getControllerSlot() != null) {
+ aInputs.add(this.getControllerSlot());
+ }
+ return aInputs;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_LargeRocketEngine.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_LargeRocketEngine.java
new file mode 100644
index 0000000000..e77ac454ee
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_LargeRocketEngine.java
@@ -0,0 +1,524 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Dynamo;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+import static gregtech.api.util.GT_Utility.filterValidMTEs;
+import static gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase.GTPPHatchElement.AirIntake;
+import static gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase.GTPPHatchElement.TTDynamo;
+
+import java.util.ArrayList;
+
+import net.minecraft.block.Block;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.fluids.Fluid;
+import net.minecraftforge.fluids.FluidStack;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.google.common.collect.ImmutableMap;
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.GT_Values;
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.recipe.check.SimpleCheckRecipeResult;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.shutdown.ShutDownReasonRegistry;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.item.chemistry.RocketFuels;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.material.MISC_MATERIALS;
+import gtPlusPlus.core.util.minecraft.FluidUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_AirIntake;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_LargeRocketEngine
+ extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_LargeRocketEngine> implements ISurvivalConstructable {
+
+ protected int fuelConsumption;
+ protected int fuelValue;
+ protected int fuelRemaining;
+ protected int freeFuelTicks = 0;
+ protected int euProduction = 0;
+ protected boolean boostEu;
+
+ public static String mLubricantName = "Carbon Dioxide";
+ public static String mCoolantName = "Liquid Hydrogen";
+
+ public static String mCasingName = "Turbodyne Casing";
+ public static String mIntakeHatchName = "Tungstensteel Turbine Casing";
+ public static String mGearboxName = "Inconel Reinforced Casing";
+
+ private static Fluid sAirFluid = null;
+ private static FluidStack sAirFluidStack = null;
+
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_LargeRocketEngine> STRUCTURE_DEFINITION = null;
+
+ private static final int CASING_ID = TAE.getIndexFromPage(3, 11);
+
+ public GregtechMetaTileEntity_LargeRocketEngine(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ this.fuelConsumption = 0;
+ this.fuelValue = 0;
+ this.fuelRemaining = 0;
+ this.boostEu = false;
+ setAir();
+ }
+
+ public GregtechMetaTileEntity_LargeRocketEngine(final String aName) {
+ super(aName);
+ this.fuelConsumption = 0;
+ this.fuelValue = 0;
+ this.fuelRemaining = 0;
+ this.boostEu = false;
+ setAir();
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Large Rocket Engine")
+ .addInfo("Generating Power from Rocket Fuels - Supports TecTech Multi-Amp Dynamos!")
+ .addInfo("Supply GT++ Rocket Fuels and 1000L of " + mLubricantName + " per hour")
+ .addInfo("Produces as much energy as you put fuel in, with optional boosting")
+ .addInfo("This multi doesn't accept fluids if not enabled - enable it first!")
+ .addInfo("Consumes 2000L/s of air and pollutes 1500 gibbl/s per 16384 eu/t produced")
+ .addInfo("Place 1-8 Air Intake Hatches on the sides to maintain Air input")
+ .addInfo("If it runs out of air, it will shut down and have to be manually restarted")
+ .addInfo("Supply 3L of " + mCoolantName + " per second, per 1000 EU/t to boost")
+ .addInfo("Takes 3x the amount of " + mLubricantName + " and maintains efficiency")
+ .addInfo("Fuel efficiency starts at ~160%, falls more slowly at higher EU/t if boosted")
+ .addInfo("If producing more than 30k EU/t, fuel efficiency will be lower:")
+ .addInfo("(These thresholds are 3x higher when boosted, boosted values displayed second)")
+ .addInfo("- 75% of max fuel efficiency at 53k or 159k EU/t output energy")
+ .addInfo("- 50% of max fuel efficiency at 69k or 207k EU/t output energy")
+ .addInfo("- 25% of max fuel efficiency at 98k or 294k EU/t output energy")
+ .addInfo("formula: x = input of energy (30000^(1/3)/ x^(1/3)) * (80000^(1/3)/ x^(1/3))")
+ .addSeparator()
+ .beginStructureBlock(3, 3, 10, false)
+ .addController("Front Center")
+ .addCasingInfoMin(mCasingName, 64, false)
+ .addCasingInfoMin(mGearboxName, 8, false)
+ .addStructureHint("Air Intake Hatch", 1)
+ .addInputBus("Side center line", 1)
+ .addInputHatch("Side center line", 1)
+ .addMaintenanceHatch("Any Block Touching Inconel Reinforced Casing", 1)
+ .addDynamoHatch("Top center line", 2)
+ .addMufflerHatch("Back Center", 3)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_LargeRocketEngine> getStructureDefinition() {
+ if (this.STRUCTURE_DEFINITION == null) {
+ this.STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_LargeRocketEngine>builder()
+ .addShape(
+ this.mName,
+ transpose(
+ new String[][] { { "CTC", "CTC", "CTC", "CTC", "CTC", "CTC", "CTC", "CTC", "CTC", "CTC" },
+ { "C~C", "SIS", "SIS", "SIS", "SIS", "SIS", "SIS", "SIS", "SIS", "CMC" },
+ { "CCC", "CSC", "CSC", "CSC", "CSC", "CSC", "CSC", "CSC", "CSC", "CCC" }, }))
+ .addElement('C', ofBlock(getCasingBlock(), getCasingMeta()))
+ .addElement('I', ofBlock(getGearboxBlock(), getGearboxMeta()))
+ // side
+ .addElement(
+ 'S',
+ buildHatchAdder(GregtechMetaTileEntity_LargeRocketEngine.class)
+ .atLeast(ImmutableMap.of(AirIntake, 8, InputBus, 1, InputHatch, 3, Maintenance, 1))
+ .casingIndex(getCasingTextureIndex())
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(getCasingBlock(), getCasingMeta()))))
+ // top
+ .addElement(
+ 'T',
+ buildHatchAdder(GregtechMetaTileEntity_LargeRocketEngine.class)
+ .atLeast(ImmutableMap.of(AirIntake, 8, Dynamo.or(TTDynamo), 1, Maintenance, 1))
+ .casingIndex(getCasingTextureIndex())
+ .dot(2)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(getCasingBlock(), getCasingMeta()))))
+ .addElement('M', Muffler.newAny(getCasingTextureIndex(), 3))
+ .build();
+ }
+ return this.STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(this.mName, stackSize, hintsOnly, 1, 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 1, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ this.mCasing = 0;
+ this.mTecTechDynamoHatches.clear();
+ this.mAllDynamoHatches.clear();
+ this.mAirIntakes.clear();
+ return checkPiece(this.mName, 1, 1, 0) && this.mCasing >= 64 - 48
+ && this.mAirIntakes.size() >= 1
+ && checkHatch();
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return CASING_ID;
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(final ItemStack aStack) {
+ return this.getMaxEfficiency(aStack) > 0;
+ }
+
+ public static void setAir() {
+ if (sAirFluidStack == null) {
+ sAirFluidStack = FluidUtils.getFluidStack("air", 1);
+ }
+ if (sAirFluid == null && sAirFluidStack != null) {
+ sAirFluid = sAirFluidStack.getFluid();
+ }
+ }
+
+ public int getAir() {
+ setAir();
+ if (this.mAirIntakes.isEmpty() || this.mAirIntakes.size() <= 0) {
+ return 0;
+ } else {
+ int totalAir = 0;
+ for (GT_MetaTileEntity_Hatch_AirIntake u : this.mAirIntakes) {
+ if (u != null && u.mFluid != null) {
+ FluidStack f = u.mFluid;
+ if (f.isFluidEqual(sAirFluidStack)) {
+ totalAir += f.amount;
+ }
+ }
+ }
+ return totalAir;
+ }
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return GTPPRecipeMaps.rocketFuels;
+ }
+
+ @Override
+ public @NotNull CheckRecipeResult checkProcessing() {
+ final ArrayList<FluidStack> tFluids = this.getStoredFluids();
+ this.clearRecipeMapForAllInputHatches();
+ int aircount = getAir();
+ int aAirToConsume = this.euProduction / 100;
+ if (aircount < aAirToConsume) {
+ stopMachine(ShutDownReasonRegistry.outOfFluid(new FluidStack(sAirFluid, aAirToConsume)));
+ return SimpleCheckRecipeResult.ofFailure("no_air");
+ } else {
+ int aTotalAir = 0;
+ for (GT_MetaTileEntity_Hatch_AirIntake aAirHatch : this.mAirIntakes) {
+ if (aAirHatch.mFluid != null) {
+ aTotalAir += aAirHatch.getFluidAmount();
+ }
+ }
+ if (aTotalAir >= aAirToConsume) {
+ int aSplitAmount = (aAirToConsume / this.mAirIntakes.size());
+ if (aSplitAmount > 0) {
+ for (GT_MetaTileEntity_Hatch_AirIntake aAirHatch : mAirIntakes) {
+ boolean hasIntakeAir = aAirHatch.drain(aSplitAmount, true) != null;
+ if (!hasIntakeAir) {
+ this.freeFuelTicks = 0;
+ return SimpleCheckRecipeResult.ofFailure("no_air");
+ }
+ }
+ }
+ }
+ }
+ // reset fuel ticks in case it does not reset when it stops
+ if (this.freeFuelTicks != 0 && this.mProgresstime == 0 && this.mEfficiency == 0) this.freeFuelTicks = 0;
+
+ if (tFluids.size() > 0 && getRecipeMap() != null) {
+ if (this.mRuntime % 72 == 0) {
+ if (!consumeCO2()) {
+ this.freeFuelTicks = 0;
+ return SimpleCheckRecipeResult.ofFailure("no_co2");
+ }
+ }
+ if (this.freeFuelTicks == 0) {
+ this.boostEu = consumeLOH();
+ }
+ for (final FluidStack hatchFluid1 : tFluids) {
+ if (hatchFluid1.isFluidEqual(sAirFluidStack)) {
+ continue;
+ }
+ if (this.freeFuelTicks == 0) {
+ for (final GT_Recipe aFuel : getRecipeMap().getAllRecipes()) {
+ final FluidStack tLiquid;
+ tLiquid = aFuel.mFluidInputs[0];
+ if (hatchFluid1.isFluidEqual(tLiquid)) {
+ if (!consumeFuel(aFuel, hatchFluid1.amount)) {
+ continue;
+ }
+ this.fuelValue = aFuel.mSpecialValue * 3;
+ this.fuelRemaining = hatchFluid1.amount;
+ this.lEUt = ((this.mEfficiency < 2000) ? 0 : GT_Values.V[5] << 1);
+ this.mProgresstime = 1;
+ this.mMaxProgresstime = 1;
+ this.mEfficiencyIncrease = this.euProduction / 2000;
+ return CheckRecipeResultRegistry.GENERATING;
+ }
+ }
+ } else {
+ this.mEfficiencyIncrease = this.euProduction / 2000;
+ this.freeFuelTicks--;
+ this.lEUt = ((this.mEfficiency < 1000) ? 0 : GT_Values.V[5] << 1);
+ this.mProgresstime = 1;
+ this.mMaxProgresstime = 1;
+ return CheckRecipeResultRegistry.GENERATING;
+ }
+ }
+ }
+ this.lEUt = 0;
+ this.mEfficiency = 0;
+ this.freeFuelTicks = 0;
+ return CheckRecipeResultRegistry.NO_FUEL_FOUND;
+ }
+
+ /**
+ * Consumes Fuel if required. Free Fuel Ticks are handled here.
+ *
+ * @param aFuel
+ * @return
+ */
+ public boolean consumeFuel(GT_Recipe aFuel, int amount) {
+ amount *= this.boostEu ? 0.3 : 0.9;
+ this.freeFuelTicks = 0;
+ int value = aFuel.mSpecialValue * 3;
+ int energy = value * amount;
+ if (amount < 5) return false;
+ FluidStack tLiquid = FluidUtils.getFluidStack(aFuel.mFluidInputs[0], (this.boostEu ? amount * 3 : amount));
+ if (!this.depleteInput(tLiquid)) {
+ return false;
+ } else {
+ this.fuelConsumption = this.boostEu ? amount * 3 : amount;
+ this.freeFuelTicks = 20;
+ setEUProduction(energy);
+ return true;
+ }
+ }
+
+ public void setEUProduction(int energy) {
+ energy /= 20;
+ double energyEfficiency;
+ double tDivideEnergy = Math.cbrt(energy);
+ if (energy > 30000) {
+ // cbrt(30 000) /
+ energyEfficiency = (31.072325 / tDivideEnergy);
+ if (energy >= 80000)
+ // cbrt(80 000) /
+ energyEfficiency *= (43.0886938 / tDivideEnergy);
+ energyEfficiency *= energy;
+ } else {
+ energyEfficiency = energy;
+ }
+ this.euProduction = (int) (energyEfficiency);
+ if (this.boostEu) this.euProduction *= 3;
+ }
+
+ public boolean consumeCO2() {
+ return this.depleteInput(MISC_MATERIALS.CARBON_DIOXIDE.getFluidStack(this.boostEu ? 3 : 1))
+ || this.depleteInput(FluidUtils.getFluidStack("carbondioxide", (this.boostEu ? 3 : 1)));
+ }
+
+ public boolean consumeLOH() {
+ int LOHamount = (3 * this.euProduction) / 1000;
+ return this.depleteInput(FluidUtils.getFluidStack(RocketFuels.Liquid_Hydrogen, LOHamount)); // (40 * ((long)
+ // euProduction /
+ // 10000))
+ }
+
+ @Override
+ public boolean addEnergyOutput(long aEU) {
+ if (aEU <= 0) {
+ return true;
+ }
+ if (this.mAllDynamoHatches.size() > 0) {
+ return addEnergyOutputMultipleDynamos(aEU, true);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean addEnergyOutputMultipleDynamos(long aEU, boolean aAllowMixedVoltageDynamos) {
+ int injected = 0;
+ long totalOutput = 0;
+ long aFirstVoltageFound = -1;
+ boolean aFoundMixedDynamos = false;
+ for (GT_MetaTileEntity_Hatch aDynamo : filterValidMTEs(this.mAllDynamoHatches)) {
+ long aVoltage = aDynamo.maxEUOutput();
+ long aTotal = aDynamo.maxAmperesOut() * aVoltage;
+ // Check against voltage to check when hatch mixing
+ if (aFirstVoltageFound == -1) {
+ aFirstVoltageFound = aVoltage;
+ } else {
+ if (aFirstVoltageFound != aVoltage) {
+ aFoundMixedDynamos = true;
+ }
+ }
+ totalOutput += aTotal;
+ }
+
+ if (totalOutput < aEU || (aFoundMixedDynamos && !aAllowMixedVoltageDynamos)) {
+ explodeMultiblock();
+ return false;
+ }
+
+ long leftToInject;
+ long aVoltage;
+ int aAmpsToInject;
+ int aRemainder;
+
+ for (GT_MetaTileEntity_Hatch aDynamo : filterValidMTEs(this.mAllDynamoHatches)) {
+ leftToInject = aEU - injected;
+ aVoltage = aDynamo.maxEUOutput();
+ aAmpsToInject = (int) (leftToInject / aVoltage);
+ aRemainder = (int) (leftToInject - (aAmpsToInject * aVoltage));
+ long powerGain;
+ for (int i = 0; i < Math.min(aDynamo.maxAmperesOut(), aAmpsToInject + 1); i++) {
+ if (i == Math.min(aDynamo.maxAmperesOut(), aAmpsToInject)) {
+ powerGain = aRemainder;
+ } else {
+ powerGain = aVoltage;
+ }
+ aDynamo.getBaseMetaTileEntity()
+ .increaseStoredEnergyUnits(powerGain, false);
+ injected += powerGain;
+ }
+ }
+ return injected > 0;
+ }
+
+ public Block getCasingBlock() {
+ return ModBlocks.blockCasings4Misc;
+ }
+
+ public byte getCasingMeta() {
+ return 11;
+ }
+
+ public Block getGearboxBlock() {
+ return ModBlocks.blockCasings3Misc;
+ }
+
+ public byte getGearboxMeta() {
+ return 1;
+ }
+
+ public byte getCasingTextureIndex() {
+ return (byte) CASING_ID;
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_LargeRocketEngine(this.mName);
+ }
+
+ @Override
+ public void saveNBTData(final NBTTagCompound aNBT) {
+ aNBT.setInteger("freeFuelTicks", this.freeFuelTicks);
+ aNBT.setInteger("euProduction", this.euProduction);
+ super.saveNBTData(aNBT);
+ }
+
+ @Override
+ public void loadNBTData(final NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ this.freeFuelTicks = aNBT.getInteger("freeFuelTicks");
+ this.euProduction = aNBT.getInteger("euProduction");
+ }
+
+ @Override
+ public int getDamageToComponent(final ItemStack aStack) {
+ return 1;
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return this.euProduction;
+ }
+
+ @Override
+ public int getPollutionPerTick(final ItemStack aStack) {
+ return 75 * (this.euProduction / 10000);
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ public String[] getExtraInfoData() {
+ return new String[] { "Rocket Engine", "Current Air: " + getAir(),
+ "Current Pollution: " + getPollutionPerTick(null),
+ "Time until next fuel consumption: " + this.freeFuelTicks,
+ "Current Output: " + this.lEUt * this.mEfficiency / 10000 + " EU/t",
+ "Fuel Consumption: " + (this.fuelConsumption) + "L/s", "Fuel Value: " + this.fuelValue + " EU/L",
+ "Fuel Remaining: " + this.fuelRemaining + " Litres", "Current Efficiency: " + this.mEfficiency / 100 + "%",
+ (this.getIdealStatus() == this.getRepairStatus()) ? "No Maintainance issues" : "Needs Maintainance" };
+ }
+
+ @Override
+ public boolean isGivingInformation() {
+ return true;
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Rocket Engine";
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 1;
+ }
+
+ @Override
+ public boolean doesBindPlayerInventory() {
+ return false;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_LargeSemifluidGenerator.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_LargeSemifluidGenerator.java
new file mode 100644
index 0000000000..4403779d09
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_LargeSemifluidGenerator.java
@@ -0,0 +1,332 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Dynamo;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+import static gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase.GTPPHatchElement.TTDynamo;
+
+import java.util.ArrayList;
+
+import net.minecraft.block.Block;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.fluids.FluidStack;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.GregTech_API;
+import gregtech.api.enums.Materials;
+import gregtech.api.enums.Textures;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Dynamo;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Maintenance;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Muffler;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.recipe.check.SimpleCheckRecipeResult;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Recipe;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+
+public class GregtechMetaTileEntity_LargeSemifluidGenerator extends
+ GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_LargeSemifluidGenerator> implements ISurvivalConstructable {
+
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_LargeSemifluidGenerator> STRUCTURE_DEFINITION = null;
+
+ protected int fuelConsumption = 0;
+ protected int fuelValue = 0;
+ protected int fuelRemaining = 0;
+ protected boolean boostEu = false;
+
+ public GregtechMetaTileEntity_LargeSemifluidGenerator(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_LargeSemifluidGenerator(String aName) {
+ super(aName);
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Large Semifluid Generator")
+ .addInfo("Engine Intake Casings must not be obstructed in front (only air blocks)")
+ .addInfo("Supply Semifluid Fuels and 2000L of Lubricant per hour to run.")
+ .addInfo("Supply 80L of Oxygen per second to boost output (optional).")
+ .addInfo("Default: Produces 2048EU/t at 100% efficiency")
+ .addInfo("Boosted: Produces 6144EU/t at 150% efficiency")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 3, 4, false)
+ .addController("Front Center")
+ .addCasingInfoMin("Stable Titanium Machine Casing", 16, false)
+ .addCasingInfoMin("Steel Gear Box Machine Casing", 2, false)
+ .addCasingInfoMin("Engine Intake Machine Casing", 8, false)
+ .addInputHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .addDynamoHatch("Back Center", 2)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return Textures.BlockIcons.OVERLAY_FRONT_DIESEL_ENGINE_ACTIVE;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return Textures.BlockIcons.OVERLAY_FRONT_DIESEL_ENGINE;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return 50;
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(ItemStack aStack) {
+ return getMaxEfficiency(aStack) > 0;
+ }
+
+ @Override
+ public @NotNull CheckRecipeResult checkProcessing() {
+ ArrayList<FluidStack> tFluids = getStoredFluids();
+
+ // Check for lubricant and oxygen first, so we can compute costs ahead of time.
+ // This will allow us to check costs without needing to actually try to deplete fluids
+ // (wasting earlier fluids in the check if later fluids turn out to be insufficient).
+ FluidStack lubricant = Materials.Lubricant.getFluid(0L);
+ FluidStack oxygen = Materials.Oxygen.getGas(0L);
+ for (FluidStack hatchFluid : tFluids) {
+ if (hatchFluid.isFluidEqual(lubricant)) {
+ lubricant.amount = Math.max(lubricant.amount, hatchFluid.amount);
+ } else if (hatchFluid.isFluidEqual(oxygen)) {
+ oxygen.amount = Math.max(oxygen.amount, hatchFluid.amount);
+ }
+ }
+ boostEu = oxygen.amount >= 4L;
+ long lubricantCost = boostEu ? 2L : 1L;
+ if (lubricant.amount < lubricantCost) {
+ return SimpleCheckRecipeResult.ofFailure("no_lubricant");
+ }
+
+ for (FluidStack hatchFluid : tFluids) { // Loops through hatches
+ GT_Recipe aFuel = GTPPRecipeMaps.semiFluidFuels.getBackend()
+ .findFuel(hatchFluid);
+ if (aFuel == null) {
+ // Not a valid semi-fluid fuel.
+ continue;
+ }
+
+ int newEUt = boostEu ? 4096 : 2048;
+ fuelConsumption = newEUt / aFuel.mSpecialValue; // Calc fuel consumption
+ FluidStack tLiquid = new FluidStack(hatchFluid.getFluid(), fuelConsumption);
+ if (depleteInput(tLiquid)) { // Deplete that amount
+ // We checked beforehand, so both of these depletions should succeed.
+ // But check the return values anyway just to be safe.
+ if (boostEu) {
+ if (!depleteInput(Materials.Oxygen.getGas(4L))) {
+ return SimpleCheckRecipeResult.ofFailure("no_oxygen");
+ }
+ }
+ // Deplete Lubricant. 2000L should = 1 hour of runtime (if baseEU = 2048)
+ if (mRuntime % 72 == 0 || mRuntime == 0) {
+ if (!depleteInput(Materials.Lubricant.getFluid(lubricantCost))) {
+ return SimpleCheckRecipeResult.ofFailure("no_lubricant");
+ }
+ }
+
+ fuelValue = aFuel.mSpecialValue;
+ fuelRemaining = hatchFluid.amount; // Record available fuel
+ this.lEUt = mEfficiency < 2000 ? 0 : newEUt; // Output 0 if startup is less than 20%
+ this.mProgresstime = 1;
+ this.mMaxProgresstime = 1;
+ this.mEfficiencyIncrease = 15;
+ return CheckRecipeResultRegistry.GENERATING;
+ }
+ }
+
+ this.lEUt = 0;
+ this.mEfficiency = 0;
+ return CheckRecipeResultRegistry.NO_FUEL_FOUND;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_LargeSemifluidGenerator> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_LargeSemifluidGenerator>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "III", "CCC", "CCC", "CCC" }, { "I~I", "CGC", "CGC", "CMC" },
+ { "III", "CCC", "CCC", "CCC" }, }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntity_LargeSemifluidGenerator.class)
+ .atLeast(Muffler, InputHatch, Maintenance)
+ .casingIndex(getCasingTextureIndex())
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(getCasingBlock(), getCasingMeta()))))
+ .addElement('G', ofBlock(getGearboxBlock(), getGearboxMeta()))
+ .addElement('I', ofBlock(getIntakeBlock(), getIntakeMeta()))
+ .addElement(
+ 'M',
+ Dynamo.or(TTDynamo)
+ .newAny(getCasingTextureIndex(), 2))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 1, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 1, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ mDynamoHatches.clear();
+ return checkPiece(mName, 1, 1, 0) && mCasing >= 16 && checkHatch();
+ }
+
+ public final boolean addLargeSemifluidGeneratorList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) {
+ if (aTileEntity == null) {
+ return false;
+ } else {
+ IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+ if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Maintenance) {
+ return addToMachineList(aTileEntity, aBaseCasingIndex);
+ } else if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Muffler) {
+ return addToMachineList(aTileEntity, aBaseCasingIndex);
+ } else if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Input) {
+ return addToMachineList(aTileEntity, aBaseCasingIndex);
+ }
+ }
+ return false;
+ }
+
+ public final boolean addLargeSemifluidGeneratorBackList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) {
+ if (aTileEntity == null) {
+ return false;
+ } else {
+ IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+ if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Dynamo || this.isThisHatchMultiDynamo(aTileEntity)) {
+ return addToMachineList(aTileEntity, aBaseCasingIndex);
+ }
+ }
+ return false;
+ }
+
+ public Block getCasingBlock() {
+ return GregTech_API.sBlockCasings4;
+ }
+
+ public byte getCasingMeta() {
+ return 2;
+ }
+
+ public Block getIntakeBlock() {
+ return GregTech_API.sBlockCasings4;
+ }
+
+ public byte getIntakeMeta() {
+ return 13;
+ }
+
+ public Block getGearboxBlock() {
+ return GregTech_API.sBlockCasings2;
+ }
+
+ public byte getGearboxMeta() {
+ return 3;
+ }
+
+ public byte getCasingTextureIndex() {
+ return 50;
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_LargeSemifluidGenerator(this.mName);
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ super.saveNBTData(aNBT);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return 1;
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack aStack) {
+ return boostEu ? 15000 : 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiLargeSemiFluidGenerator;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ public String[] getExtraInfoData() {
+ return new String[] { "Large Semifluid Generator", "Current Output: " + lEUt * mEfficiency / 10000 + " EU/t",
+ "Fuel Consumption: " + fuelConsumption + "L/t", "Fuel Value: " + fuelValue + " EU/L",
+ "Fuel Remaining: " + fuelRemaining + " Litres", "Current Efficiency: " + (mEfficiency / 100) + "%",
+ getIdealStatus() == getRepairStatus() ? "No Maintainance issues" : "Needs Maintainance" };
+ }
+
+ @Override
+ public boolean isGivingInformation() {
+ return true;
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Semifluid Generator";
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 0;
+ }
+
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_MassFabricator.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_MassFabricator.java
new file mode 100644
index 0000000000..69042b7982
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_MassFabricator.java
@@ -0,0 +1,337 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.stream.Stream;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.common.util.ForgeDirection;
+import net.minecraftforge.fluids.FluidStack;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.ConfigCategories;
+import gregtech.api.enums.Materials;
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.recipe.check.SimpleCheckRecipeResult;
+import gregtech.api.util.GT_Config;
+import gregtech.api.util.GT_ModHandler;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.minecraft.ItemUtils;
+import gtPlusPlus.core.util.minecraft.MaterialUtils;
+import gtPlusPlus.core.util.minecraft.PlayerUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMetaTileEntity_MassFabricator
+ extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_MassFabricator> implements ISurvivalConstructable {
+
+ public static int sUUAperUUM = 1;
+ public static int sUUASpeedBonus = 4;
+ public static int sDurationMultiplier = 3200;
+
+ public static String mCasingName1 = "Matter Fabricator Casing";
+ public static String mCasingName2 = "Containment Casing";
+ public static String mCasingName3 = "Matter Generation Coil";
+
+ private int mMode = 0;
+
+ private static final int MODE_SCRAP = 1;
+ private static final int MODE_UU = 0;
+
+ public static boolean sRequiresUUA = false;
+ private static final FluidStack[] mUU = new FluidStack[2];
+ private static final ItemStack[] mScrap = new ItemStack[2];
+
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_MassFabricator> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_MassFabricator(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_MassFabricator(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Mass Fabricator / Recycler";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Matter Fabricator")
+ .addInfo("Speed: +0% | EU Usage: 80%")
+ .addInfo("Parallel: Scrap = 64 | UU = 8 * Tier")
+ .addInfo("Produces UU-A, UU-M & Scrap")
+ .addInfo("Change mode with screwdriver")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(5, 4, 5, true)
+ .addController("Front Center")
+ .addCasingInfoMin(mCasingName3, 9, false)
+ .addCasingInfoMin(mCasingName2, 24, false)
+ .addCasingInfoMin(mCasingName1, 36, false)
+ .addInputBus("Any Casing", 1)
+ .addOutputBus("Any Casing", 1)
+ .addInputHatch("Any Casing", 1)
+ .addOutputHatch("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addMaintenanceHatch("Any Casing", 1)
+ .addMufflerHatch("Any Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_MatterFab_Active_Animated;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_MatterFab_Animated;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return TAE.GTPP_INDEX(9);
+ }
+
+ @Override
+ public void onConfigLoad(final GT_Config aConfig) {
+ super.onConfigLoad(aConfig);
+ sDurationMultiplier = aConfig
+ .get(ConfigCategories.machineconfig, "Massfabricator.UUM_Duration_Multiplier", sDurationMultiplier);
+ sUUAperUUM = aConfig.get(ConfigCategories.machineconfig, "Massfabricator.UUA_per_UUM", sUUAperUUM);
+ sUUASpeedBonus = aConfig.get(ConfigCategories.machineconfig, "Massfabricator.UUA_Speed_Bonus", sUUASpeedBonus);
+ sRequiresUUA = aConfig.get(ConfigCategories.machineconfig, "Massfabricator.UUA_Requirement", sRequiresUUA);
+ // Materials.UUAmplifier.mChemicalFormula = ("Mass Fabricator Eff/Speed Bonus: x" + sUUASpeedBonus);
+ }
+
+ public static boolean sInit = false;
+
+ public static void init() {
+ if (!sInit) {
+ if (mScrap[0] == null) {
+ mScrap[0] = ItemUtils.getSimpleStack(ItemUtils.getItemFromFQRN("IC2:itemScrap"));
+ }
+ if (mScrap[1] == null) {
+ mScrap[1] = ItemUtils.getSimpleStack(ItemUtils.getItemFromFQRN("IC2:itemScrapbox"));
+ }
+ if (mUU[0] == null) {
+ mUU[0] = Materials.UUAmplifier.getFluid(100);
+ }
+ if (mUU[1] == null) {
+ mUU[1] = Materials.UUMatter.getFluid(100);
+ }
+ sInit = true;
+ }
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_MassFabricator> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_MassFabricator>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { "CCCCC", "CCCCC", "CCCCC", "CCCCC", "CCCCC" },
+ { "CGGGC", "G---G", "G---G", "G---G", "CGGGC" },
+ { "CGGGC", "G---G", "G---G", "G---G", "CGGGC" },
+ { "CC~CC", "CHHHC", "CHHHC", "CHHHC", "CCCCC" }, }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntity_MassFabricator.class)
+ .atLeast(InputBus, OutputBus, InputHatch, OutputHatch, Maintenance, Energy, Muffler)
+ .casingIndex(TAE.GTPP_INDEX(9))
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasingsMisc, 9))))
+ .addElement('H', ofBlock(ModBlocks.blockCasingsMisc, 8))
+ .addElement('G', ofBlock(ModBlocks.blockCasings3Misc, 15))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 2, 3, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 2, 3, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ return checkPiece(mName, 2, 3, 0) && mCasing >= 36 && checkHatch();
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiMassFabricator;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_MassFabricator(this.mName);
+ }
+
+ /**
+ * Special Recipe Handling
+ */
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return this.mMode == MODE_SCRAP ? RecipeMaps.recyclerRecipes : GTPPRecipeMaps.multiblockMassFabricatorRecipes;
+ }
+
+ @Nonnull
+ @Override
+ public Collection<RecipeMap<?>> getAvailableRecipeMaps() {
+ return Arrays.asList(RecipeMaps.recyclerRecipes, GTPPRecipeMaps.multiblockMassFabricatorRecipes);
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic() {
+
+ @NotNull
+ @Override
+ public CheckRecipeResult process() {
+ init();
+ return super.process();
+ }
+
+ @NotNull
+ @Override
+ protected CheckRecipeResult validateRecipe(@NotNull GT_Recipe recipe) {
+ if (mMode == MODE_SCRAP) {
+ if (recipe.mOutputs == null) {
+ return SimpleCheckRecipeResult.ofSuccess("no_scrap");
+ }
+ }
+ return CheckRecipeResultRegistry.SUCCESSFUL;
+ }
+
+ @Nonnull
+ @Override
+ protected Stream<GT_Recipe> findRecipeMatches(@Nullable RecipeMap<?> map) {
+ if (mMode == MODE_SCRAP) {
+ if (inputItems != null) {
+ for (ItemStack item : inputItems) {
+ if (item == null || item.stackSize == 0) continue;
+ ItemStack aPotentialOutput = GT_ModHandler
+ .getRecyclerOutput(GT_Utility.copyAmount(1, item), 0);
+ GT_Recipe recipe = new GT_Recipe(
+ false,
+ new ItemStack[] { GT_Utility.copyAmount(1, item) },
+ aPotentialOutput == null ? null : new ItemStack[] { aPotentialOutput },
+ null,
+ new int[] { 2000 },
+ null,
+ null,
+ 40,
+ MaterialUtils.getVoltageForTier(1),
+ 0);
+ return Stream.of(recipe);
+ }
+ }
+ return Stream.empty();
+ }
+ return super.findRecipeMatches(map);
+ }
+ }.setEuModifier(0.8F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ protected void setupProcessingLogic(ProcessingLogic logic) {
+ super.setupProcessingLogic(logic);
+ logic.enablePerfectOverclock();
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return this.mMode == MODE_SCRAP ? 64 : 8 * (Math.max(1, GT_Utility.getTier(getMaxInputVoltage())));
+ }
+
+ @Override
+ public void onModeChangeByScrewdriver(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+ int aMode = this.mMode + 1;
+ if (aMode > 1) {
+ this.mMode = MODE_UU;
+ PlayerUtils.messagePlayer(aPlayer, "Mode [" + this.mMode + "]: Matter/AmpliFabricator");
+ } else if (aMode == 1) {
+ this.mMode = MODE_SCRAP;
+ PlayerUtils.messagePlayer(aPlayer, "Mode [" + this.mMode + "]: Recycler");
+ } else {
+ this.mMode = MODE_SCRAP;
+ PlayerUtils.messagePlayer(aPlayer, "Mode [" + this.mMode + "]: Recycler");
+ }
+ mLastRecipe = null;
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ aNBT.setInteger("mMode", mMode);
+ super.saveNBTData(aNBT);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ mMode = aNBT.getInteger("mMode");
+ super.loadNBTData(aNBT);
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_QuantumForceTransformer.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_QuantumForceTransformer.java
new file mode 100644
index 0000000000..bd5e579cd2
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_QuantumForceTransformer.java
@@ -0,0 +1,939 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.lazy;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.withChannel;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.ExoticEnergy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_OreDictUnificator.getAssociation;
+import static gregtech.api.util.GT_ParallelHelper.addFluidsLong;
+import static gregtech.api.util.GT_ParallelHelper.addItemsLong;
+import static gregtech.api.util.GT_ParallelHelper.calculateChancedOutputMultiplier;
+import static gregtech.api.util.GT_RecipeBuilder.BUCKETS;
+import static gregtech.api.util.GT_RecipeBuilder.INGOTS;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import net.minecraft.block.Block;
+import net.minecraft.client.renderer.RenderBlocks;
+import net.minecraft.client.renderer.Tessellator;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.IIcon;
+import net.minecraft.util.StatCollector;
+import net.minecraft.world.IBlockAccess;
+import net.minecraftforge.common.util.ForgeDirection;
+import net.minecraftforge.fluids.Fluid;
+import net.minecraftforge.fluids.FluidStack;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.ITierConverter;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+import com.gtnewhorizon.structurelib.structure.StructureUtility;
+
+import cpw.mods.fml.relauncher.Side;
+import cpw.mods.fml.relauncher.SideOnly;
+import gregtech.api.enums.GT_Values;
+import gregtech.api.enums.Materials;
+import gregtech.api.enums.TAE;
+import gregtech.api.enums.Textures;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_ExtendedPowerMultiBlockBase;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input;
+import gregtech.api.objects.ItemData;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.recipe.check.SimpleCheckRecipeResult;
+import gregtech.api.render.TextureFactory;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_ParallelHelper;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.GT_Utility;
+import gregtech.api.util.shutdown.ShutDownReasonRegistry;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.material.ELEMENT;
+import gtPlusPlus.core.util.minecraft.ItemUtils;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+@SuppressWarnings("SpellCheckingInspection")
+public class GregtechMetaTileEntity_QuantumForceTransformer
+ extends GT_MetaTileEntity_ExtendedPowerMultiBlockBase<GregtechMetaTileEntity_QuantumForceTransformer>
+ implements ISurvivalConstructable {
+
+ private int mCasing;
+ protected int mCraftingTier = 0;
+ protected int mFocusingTier = 0;
+ protected int mMaxParallel = 0;
+ private boolean mFluidMode = false, doFermium = false, doNeptunium = false;
+ private static final Fluid mNeptunium = ELEMENT.getInstance().NEPTUNIUM.getPlasma();
+ private static final Fluid mFermium = ELEMENT.getInstance().FERMIUM.getPlasma();
+ private static final String MAIN_PIECE = "main";
+ private GT_MetaTileEntity_Hatch_Input mNeptuniumHatch;
+ private GT_MetaTileEntity_Hatch_Input mFermiumHatch;
+ private static final IStructureDefinition<GregtechMetaTileEntity_QuantumForceTransformer> STRUCTURE_DEFINITION = StructureDefinition
+ .<GregtechMetaTileEntity_QuantumForceTransformer>builder()
+ .addShape(
+ MAIN_PIECE,
+ new String[][] { // A - 142, B - 234, C - 177, D - 96, E - 224, H - 36, M - 21
+ { " ", " ", " ", " ", " ",
+ " ", " ", " ", " ", " ",
+ " ", " ", " ", " BAB ", " BBBBABBBB ",
+ " BAAAAAAAB ", " BABBABBAB ", " BA AB ", " A A ", " A A ",
+ " A A " },
+ { " ", " ", " ", " ", " ",
+ " ", " ", " ", " ", " ",
+ " ", " ", " BAB ", " AAABBBAAA ", " BAAAAAAAAAB ",
+ " B B ", " A A ", " A A ", " ", " ",
+ " " },
+ { " ", " ", " ", " ", " ",
+ " ", " ", " ", " ", " ",
+ " ", " BAB ", " AA AA ", " AA AA ", " BAA AAB ",
+ " B B ", " A A ", " A A ", " ", " ",
+ " " },
+ { " ", " ", " ", " ", " ",
+ " ", " ", " ", " ", " ",
+ " ", " BAAAB ", " AA AA ", " AA AA ", "BAA AAB",
+ "B B", "A A", "A A", "A A", "A A",
+ "A A" },
+ { " TTT ", " EEE ", " EEE ", " EEE ", " DDD ",
+ " EEE ", " DDD ", " EEE ", " EEE ", " EEE ",
+ " DDD ", " BAEEEAB ", " AA EEE AA ", " A EEE A ", "BA DDD AB",
+ "B EEE B", "B DDD B", " EEE ", " EEE ", " EEE ",
+ " Z~X " },
+ { " TTTTT ", " ECCCE ", " ECCCE ", " ECCCE ", " D D ",
+ " ECCCE ", " D D ", " ECCCE ", " ECCCE ", " ECCCE ",
+ " D D ", " BAECCCEAB ", " A ECCCE A ", " A ECCCE A ", "BA D D AB",
+ "B ECCCE B", "B D D B", "B ECCCE B", " ECCCE ", " ECCCE ",
+ " HHHHH " },
+ { " TTTTTTT ", " ECCCCCE ", " EC CE ", " EC CE ", " D D ",
+ " EC CE ", " D D ", " EC CE ", " EC CE ", " EC CE ",
+ " D D ", " BAEC CEAB ", " B EC CE B ", "BB EC CE BB", "BA D D AB",
+ "A EC CE A", "A D D A", "A EC CE A", " EC CE ", " EC CE ",
+ " HHHHHHH " },
+ { " TTTTTTT ", " ECCCCCE ", " EC CE ", " EC CE ", " D D ",
+ " EC CE ", " D D ", " EC CE ", " EC CE ", " EC CE ",
+ " D D ", " AAEC CEAA ", " A EC CE A ", "AB EC CE BA", "AA D D AA",
+ "A EC CE A", "A D D A", " EC CE ", " EC CE ", " EC CE ",
+ " HHHHHHH " },
+ { " TTTTTTT ", " ECCCCCE ", " EC CE ", " EC CE ", " D D ",
+ " EC CE ", " D D ", " EC CE ", " EC CE ", " EC CE ",
+ " D D ", " BAEC CEAB ", " B EC CE B ", "BB EC CE BB", "BA D D AB",
+ "A EC CE A", "A D D A", "A EC CE A", " EC CE ", " EC CE ",
+ " HHHHHHH " },
+ { " TTTTT ", " ECCCE ", " ECCCE ", " ECCCE ", " D D ",
+ " ECCCE ", " D D ", " ECCCE ", " ECCCE ", " ECCCE ",
+ " D D ", " BAECCCEAB ", " A ECCCE A ", " A ECCCE A ", "BA D D AB",
+ "B ECCCE B", "B D D B", "B ECCCE B", " ECCCE ", " ECCCE ",
+ " HHHHH " },
+ { " TTT ", " EEE ", " EEE ", " EEE ", " DDD ",
+ " EEE ", " DDD ", " EEE ", " EEE ", " EEE ",
+ " DDD ", " BAEEEAB ", " AA EEE AA ", " A EEE A ", "BA DDD AB",
+ "B EEE B", "B DDD B", " EEE ", " EEE ", " EEE ",
+ " HHH " },
+ { " ", " ", " ", " ", " ",
+ " ", " ", " ", " ", " ",
+ " ", " BAAAB ", " AA AA ", " AA AA ", "BAA AAB",
+ "B B", "A A", "A A", "A A", "A A",
+ "A A" },
+ { " ", " ", " ", " ", " ",
+ " ", " ", " ", " ", " ",
+ " ", " BAB ", " AA AA ", " AA AA ", " BAA AAB ",
+ " B B ", " A A ", " A A ", " ", " ",
+ " " },
+ { " ", " ", " ", " ", " ",
+ " ", " ", " ", " ", " ",
+ " ", " ", " BAB ", " AAABBBAAA ", " BAAAAAAAAAB ",
+ " B B ", " A A ", " A A ", " ", " ",
+ " " },
+ { " ", " ", " ", " ", " ",
+ " ", " ", " ", " ", " ",
+ " ", " ", " ", " BAB ", " BBBBABBBB ",
+ " BBBAAABBB ", " ABBAAABBA ", " A BA AB A ", " A A ", " A A ",
+ " A A " }, })
+ .addElement(
+ 'A',
+ withChannel(
+ "manipulator",
+ StructureUtility.ofBlocksTiered(
+ craftingTierConverter(),
+ getAllCraftingTiers(),
+ 0,
+ GregtechMetaTileEntity_QuantumForceTransformer::setCraftingTier,
+ GregtechMetaTileEntity_QuantumForceTransformer::getCraftingTier)))
+ .addElement(
+ 'B',
+ withChannel(
+ "shielding",
+ StructureUtility.ofBlocksTiered(
+ focusingTierConverter(),
+ getAllFocusingTiers(),
+ 0,
+ GregtechMetaTileEntity_QuantumForceTransformer::setFocusingTier,
+ GregtechMetaTileEntity_QuantumForceTransformer::getFocusingTier)))
+ .addElement('C', ofBlock(ModBlocks.blockCasings4Misc, 4))
+ .addElement('D', ofBlock(ModBlocks.blockCasings2Misc, 12))
+ .addElement('E', lazy(t -> ofBlock(t.getCasingBlock1(), t.getCasingMeta1())))
+ .addElement(
+ 'H',
+ buildHatchAdder(GregtechMetaTileEntity_QuantumForceTransformer.class)
+ .atLeast(InputBus, InputHatch, Maintenance, Energy.or(ExoticEnergy))
+ .casingIndex(TAE.getIndexFromPage(0, 10))
+ .dot(4)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings2Misc, 12))))
+ .addElement(
+ 'T',
+ buildHatchAdder(GregtechMetaTileEntity_QuantumForceTransformer.class)
+ .atLeast(OutputBus, OutputHatch, Maintenance)
+ .casingIndex(TAE.getIndexFromPage(0, 10))
+ .dot(5)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings2Misc, 12))))
+ .addElement(
+ 'Z',
+ buildHatchAdder(GregtechMetaTileEntity_QuantumForceTransformer.class)
+ .hatchClass(GT_MetaTileEntity_Hatch_Input.class)
+ .adder(GregtechMetaTileEntity_QuantumForceTransformer::addNeptuniumHatch)
+ .casingIndex(TAE.getIndexFromPage(0, 10))
+ .dot(5)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings2Misc, 12))))
+ .addElement(
+ 'X',
+ buildHatchAdder(GregtechMetaTileEntity_QuantumForceTransformer.class)
+ .hatchClass(GT_MetaTileEntity_Hatch_Input.class)
+ .adder(GregtechMetaTileEntity_QuantumForceTransformer::addFermiumHatch)
+ .casingIndex(TAE.getIndexFromPage(0, 10))
+ .dot(5)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings2Misc, 12))))
+ .build();
+
+ public GregtechMetaTileEntity_QuantumForceTransformer(final int aID, final String aName,
+ final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_QuantumForceTransformer(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_QuantumForceTransformer(this.mName);
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType("Quantum Force Transformer")
+ .addInfo("Controller Block for the Quantum Force Transformer")
+ .addInfo("Allows Complex chemical lines to be performed instantly in one step")
+ .addInfo("Every recipe requires a catalyst, each catalyst adds 1 parallel and lasts forever")
+ .addInfo("Accepts TecTech Energy and Laser Hatches")
+ .addInfo("All inputs go on the bottom, all outputs go on the top")
+ .addInfo("Put a circuit in the controller to specify the focused output")
+ .addInfo("Check NEI to see the order of outputs, and which circuit number you need.")
+ .addInfo("If separate input busses are enabled put the circuit in the circuit slot of the bus")
+ .addInfo("Uses FocusTier*4*sqrt(parallels) Neptunium Plasma if focusing")
+ .addInfo("Can use FocusTier*4*sqrt(parallels) Fermium Plasma for additional chance output")
+ .addInfo("Use a screwdriver to enable Fluid mode")
+ .addInfo(
+ "Fluid mode turns all possible outputs into their fluid variant, those which can't are left as they were.")
+ .addInfo("This multi gets improved when all casings of some types are upgraded")
+ .addInfo("Casing functions:")
+ .addInfo("Pulse Manipulators: Recipe Tier Allowed (check NEI for the tier of each recipe)")
+ .addInfo("Shielding Cores: Focusing Tier (equal to or higher than recipe tier to allow focus)")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(15, 21, 15, true)
+ .addController("Bottom Center")
+ .addCasingInfoMin("Bulk Production Frame", 80, false)
+ .addCasingInfoMin("Quantum Force Conductor", 177, false)
+ .addCasingInfoMin("Force Field Glass", 224, false)
+ .addCasingInfoMin("Pulse Manipulators", 236, true)
+ .addCasingInfoMin("Shielding Cores", 142, true)
+ .addInputBus(EnumChatFormatting.BLUE + "Bottom" + EnumChatFormatting.GRAY + " Layer", 4)
+ .addInputHatch(EnumChatFormatting.BLUE + "Bottom" + EnumChatFormatting.GRAY + " Layer", 4)
+ .addOutputHatch(EnumChatFormatting.AQUA + "Top" + EnumChatFormatting.GRAY + " Layer", 5)
+ .addOutputBus(EnumChatFormatting.AQUA + "Top" + EnumChatFormatting.GRAY + " Layer", 5)
+ .addEnergyHatch(EnumChatFormatting.BLUE + "Bottom" + EnumChatFormatting.GRAY + " Layer", 4)
+ .addMaintenanceHatch(
+ EnumChatFormatting.BLUE + "Bottom"
+ + EnumChatFormatting.GRAY
+ + " or "
+ + EnumChatFormatting.AQUA
+ + "Top"
+ + EnumChatFormatting.GRAY
+ + " Layer",
+ 4,
+ 5)
+ .addStructureInfo(
+ EnumChatFormatting.WHITE + "Neptunium Plasma Hatch: "
+ + EnumChatFormatting.GREEN
+ + "Left"
+ + EnumChatFormatting.GRAY
+ + " side of Controller")
+ .addStructureInfo(
+ EnumChatFormatting.WHITE + "Fermium Plasma Hatch: "
+ + EnumChatFormatting.DARK_GREEN
+ + "Right"
+ + EnumChatFormatting.GRAY
+ + " side of Controller")
+ .toolTipFinisher(
+ GT_Values.AuthorBlueWeabo + EnumChatFormatting.RESET
+ + EnumChatFormatting.GREEN
+ + " + Steelux"
+ + EnumChatFormatting.RESET
+ + " - [GT++]");
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_QuantumForceTransformer> getStructureDefinition() {
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ this.mCasing = 0;
+ this.mCraftingTier = 0;
+ this.mFocusingTier = 0;
+ if (!checkPiece(MAIN_PIECE, 7, 20, 4)) {
+ return false;
+ }
+
+ if (mMaintenanceHatches.size() != 1 || mOutputBusses.isEmpty() || mOutputHatches.isEmpty()) {
+ return false;
+ }
+
+ return checkExoticAndNormalEnergyHatches();
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(MAIN_PIECE, stackSize, hintsOnly, 7, 20, 4);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(MAIN_PIECE, stackSize, 7, 20, 4, elementBudget, env, false, true);
+ }
+
+ public static List<Pair<Block, Integer>> getAllCraftingTiers() {
+ return new ArrayList<>() {
+
+ {
+ add(Pair.of(ModBlocks.blockCasings5Misc, 7));
+ add(Pair.of(ModBlocks.blockCasings5Misc, 8));
+ add(Pair.of(ModBlocks.blockCasings5Misc, 9));
+ add(Pair.of(ModBlocks.blockCasings5Misc, 10));
+ }
+ };
+ }
+
+ public static List<Pair<Block, Integer>> getAllFocusingTiers() {
+ return new ArrayList<>() {
+
+ {
+ add(Pair.of(ModBlocks.blockCasings5Misc, 11));
+ add(Pair.of(ModBlocks.blockCasings5Misc, 12));
+ add(Pair.of(ModBlocks.blockCasings5Misc, 13));
+ add(Pair.of(ModBlocks.blockCasings5Misc, 14));
+ }
+ };
+ }
+
+ public static ITierConverter<Integer> craftingTierConverter() {
+ return (block, meta) -> {
+ if (block == null) {
+ return -1;
+ } else if (block == ModBlocks.blockCasings5Misc) { // Resonance Chambers
+ switch (meta) {
+ case 7 -> {
+ return 1;
+ }
+ case 8 -> {
+ return 2;
+ }
+ case 9 -> {
+ return 3;
+ }
+ case 10 -> {
+ return 4;
+ }
+ }
+ }
+ return -1;
+ };
+ }
+
+ public static ITierConverter<Integer> focusingTierConverter() {
+ return (block, meta) -> {
+ if (block == null) {
+ return -1;
+ } else if (block == ModBlocks.blockCasings5Misc) { // Generation Coils
+ switch (meta) {
+ case 11 -> {
+ return 1;
+ }
+ case 12 -> {
+ return 2;
+ }
+ case 13 -> {
+ return 3;
+ }
+ case 14 -> {
+ return 4;
+ }
+ }
+ }
+ return -1;
+ };
+ }
+
+ private void setCraftingTier(int tier) {
+ mCraftingTier = tier;
+ }
+
+ private void setFocusingTier(int tier) {
+ mFocusingTier = tier;
+ }
+
+ private int getCraftingTier() {
+ return mCraftingTier;
+ }
+
+ private int getFocusingTier() {
+ return mFocusingTier;
+ }
+
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active;
+ }
+
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced;
+ }
+
+ protected int getCasingTextureId() {
+ return TAE.getIndexFromPage(0, 10);
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return GTPPRecipeMaps.quantumForceTransformerRecipes;
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(final ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic() {
+
+ private int[] chances;
+ private FluidStack[] fluidModeItems;
+
+ @NotNull
+ @Override
+ protected CheckRecipeResult validateRecipe(@NotNull GT_Recipe recipe) {
+ if (recipe.mSpecialValue > getCraftingTier()) {
+ return CheckRecipeResultRegistry.insufficientMachineTier(recipe.mSpecialValue);
+ }
+ ItemStack catalyst = null;
+ for (ItemStack item : recipe.mInputs) {
+ if (ItemUtils.isCatalyst(item)) {
+ catalyst = item;
+ break;
+ }
+ }
+
+ if (catalyst == null) {
+ return SimpleCheckRecipeResult.ofFailure("no_catalyst");
+ }
+
+ maxParallel = 0;
+ for (ItemStack item : inputItems) {
+ if (ItemUtils.isCatalyst(item) && item.isItemEqual(catalyst)) {
+ maxParallel += item.stackSize;
+ }
+ }
+
+ mMaxParallel = maxParallel;
+ doFermium = false;
+ doNeptunium = false;
+
+ if (recipe.mSpecialValue <= getFocusingTier()) {
+ if (drain(mFermiumHatch, new FluidStack(mFermium, 1), false)) {
+ doFermium = true;
+ }
+ if (drain(mNeptuniumHatch, new FluidStack(mNeptunium, 1), false)) {
+ doNeptunium = true;
+ }
+ }
+
+ chances = getOutputChances(recipe, doNeptunium ? findProgrammedCircuitNumber() : -1);
+
+ // Handle Fluid Mode. Add fluid that item can be turned into to fluidModeItems.
+ // null if Fluid Mode is disabled or item cannot be turned into fluid.
+ fluidModeItems = new FluidStack[recipe.mOutputs.length];
+ if (mFluidMode) {
+ for (int i = 0; i < recipe.mOutputs.length; i++) {
+ ItemStack item = recipe.getOutput(i);
+ if (item == null) continue;
+ ItemData data = getAssociation(item);
+ Materials mat = data == null ? null : data.mMaterial.mMaterial;
+ if (mat != null) {
+ if (mat.mStandardMoltenFluid != null) {
+ fluidModeItems[i] = mat.getMolten(INGOTS);
+ } else if (mat.mFluid != null) {
+ fluidModeItems[i] = mat.getFluid(BUCKETS);
+ }
+ }
+ }
+ }
+
+ return CheckRecipeResultRegistry.SUCCESSFUL;
+ }
+
+ @NotNull
+ @Override
+ public GT_ParallelHelper createParallelHelper(@Nonnull GT_Recipe recipe) {
+ return super.createParallelHelper(recipe).setCustomItemOutputCalculation(parallel -> {
+ ArrayList<ItemStack> items = new ArrayList<>();
+
+ for (int i = 0; i < recipe.mOutputs.length; i++) {
+ ItemStack item = recipe.getOutput(i);
+ if (item == null || fluidModeItems[i] != null) continue;
+ ItemStack itemToAdd = item.copy();
+ double outputMultiplier = calculateChancedOutputMultiplier(chances[i], parallel);
+ long itemAmount = (long) (item.stackSize * outputMultiplier);
+ addItemsLong(items, itemToAdd, itemAmount);
+ }
+
+ return items.toArray(new ItemStack[0]);
+ })
+ .setCustomFluidOutputCalculation(parallel -> {
+ ArrayList<FluidStack> fluids = new ArrayList<>();
+
+ if (mFluidMode) {
+ for (int i = 0; i < recipe.mOutputs.length; i++) {
+ FluidStack fluid = fluidModeItems[i];
+ if (fluid == null) continue;
+ FluidStack fluidToAdd = fluid.copy();
+ double outputMultiplier = calculateChancedOutputMultiplier(chances[i], parallel);
+ int itemAmount = recipe.mOutputs[i].stackSize;
+ long fluidAmount = (long) (fluidToAdd.amount * outputMultiplier * itemAmount);
+ addFluidsLong(fluids, fluidToAdd, fluidAmount);
+ }
+ }
+
+ for (int i = 0; i < recipe.mFluidOutputs.length; i++) {
+ FluidStack fluid = recipe.getFluidOutput(i);
+ if (fluid == null) continue;
+ FluidStack fluidToAdd = fluid.copy();
+ double outputMultiplier = calculateChancedOutputMultiplier(
+ chances[i + recipe.mOutputs.length],
+ parallel);
+ long fluidAmount = (long) (fluidToAdd.amount * outputMultiplier);
+ addFluidsLong(fluids, fluidToAdd, fluidAmount);
+ }
+
+ return fluids.toArray(new FluidStack[0]);
+ });
+ }
+
+ private int findProgrammedCircuitNumber() {
+ if (isInputSeparationEnabled()) {
+ for (ItemStack stack : inputItems) {
+ if (GT_Utility.isAnyIntegratedCircuit(stack)) {
+ return stack.getItemDamage() - 1;
+ }
+ }
+ return -1;
+ } else {
+ final ItemStack controllerStack = getControllerSlot();
+ return GT_Utility.isAnyIntegratedCircuit(controllerStack) ? controllerStack.getItemDamage() - 1
+ : -1;
+ }
+ }
+ };
+ }
+
+ @Override
+ protected void setProcessingLogicPower(ProcessingLogic logic) {
+ logic.setAvailableVoltage(getAverageInputVoltage());
+ logic.setAvailableAmperage(getMaxInputAmps());
+ }
+
+ private byte runningTick = 0;
+
+ @Override
+ public boolean onRunningTick(ItemStack aStack) {
+ if (!super.onRunningTick(aStack)) {
+ return false;
+ }
+
+ if (runningTick % 20 == 0) {
+ int amount = (int) (getFocusingTier() * 4
+ * Math.sqrt(Math.min(mMaxParallel, processingLogic.getCurrentParallels())));
+ if (doFermium) {
+ FluidStack fermiumToConsume = new FluidStack(mFermium, amount);
+ if (!drain(mFermiumHatch, fermiumToConsume, true)) {
+ doFermium = false;
+ stopMachine(ShutDownReasonRegistry.outOfFluid(fermiumToConsume));
+ return false;
+ }
+ }
+
+ if (doNeptunium) {
+ FluidStack neptuniumToConsume = new FluidStack(mNeptunium, amount);
+ if (!drain(mNeptuniumHatch, neptuniumToConsume, true)) {
+ doNeptunium = false;
+ stopMachine(ShutDownReasonRegistry.outOfFluid(neptuniumToConsume));
+ return false;
+ }
+ }
+
+ runningTick = 1;
+ } else {
+ runningTick++;
+ }
+
+ return true;
+ }
+
+ @Override
+ public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {
+ super.onPostTick(aBaseMetaTileEntity, aTick);
+ if (aBaseMetaTileEntity.isServerSide()) {
+ // TODO: Look for proper fix
+ // Updates every 30 sec
+ if (mUpdate <= -550) mUpdate = 50;
+ }
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public int getDamageToComponent(final ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ private int[] getOutputChances(GT_Recipe tRecipe, int aChanceIncreased) {
+ int difference = getFocusingTier() - tRecipe.mSpecialValue;
+ int aOutputsAmount = tRecipe.mOutputs.length + tRecipe.mFluidOutputs.length;
+ int aChancePerOutput = 10000 / aOutputsAmount;
+ int[] tChances = new int[aOutputsAmount];
+ Arrays.fill(tChances, aChancePerOutput);
+
+ switch (difference) {
+ case 0 -> {
+ for (int i = 0; i < tChances.length; i++) {
+ if (doNeptunium) {
+ if (i == aChanceIncreased) {
+ tChances[i] += aChancePerOutput / 2 * (aOutputsAmount - 1);
+ } else {
+ tChances[i] /= 2;
+ }
+ }
+
+ if (doFermium) {
+ tChances[i] += (10000 - tChances[i]) / 4;
+ }
+ }
+ }
+ case 1 -> {
+ for (int i = 0; i < tChances.length; i++) {
+ if (doNeptunium) {
+ if (i == aChanceIncreased) {
+ tChances[i] += aChancePerOutput * 3 / 4 * (aOutputsAmount - 1);
+ } else {
+ tChances[i] /= 4;
+ }
+ }
+
+ if (doFermium) {
+ tChances[i] += (10000 - tChances[i]) / 3;
+ }
+ }
+ }
+ case 2, 3 -> {
+ for (int i = 0; i < tChances.length; i++) {
+ if (doNeptunium) {
+ if (i == aChanceIncreased) {
+ tChances[i] = 10000;
+ } else {
+ tChances[i] = 0;
+ }
+ }
+
+ if (doFermium) {
+ tChances[i] += (10000 - tChances[i]) / 2;
+ }
+ }
+ }
+ }
+ return tChances;
+ }
+
+ @Override
+ public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+ mFluidMode = !mFluidMode;
+ GT_Utility.sendChatToPlayer(
+ aPlayer,
+ StatCollector.translateToLocal("miscutils.machines.QFTFluidMode") + " " + mFluidMode);
+ }
+
+ public boolean addNeptuniumHatch(IGregTechTileEntity aTileEntity, short aBaseCasingIndex) {
+ if (aTileEntity == null) return false;
+ IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+ if (aMetaTileEntity == null) return false;
+ if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Input) {
+ ((GT_MetaTileEntity_Hatch) aMetaTileEntity).updateTexture(aBaseCasingIndex);
+ ((GT_MetaTileEntity_Hatch_Input) aMetaTileEntity).mRecipeMap = null;
+ mNeptuniumHatch = (GT_MetaTileEntity_Hatch_Input) aMetaTileEntity;
+ return true;
+ }
+ return false;
+ }
+
+ public boolean addFermiumHatch(IGregTechTileEntity aTileEntity, short aBaseCasingIndex) {
+ if (aTileEntity == null) return false;
+ IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+ if (aMetaTileEntity == null) return false;
+ if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Input) {
+ ((GT_MetaTileEntity_Hatch) aMetaTileEntity).updateTexture(aBaseCasingIndex);
+ ((GT_MetaTileEntity_Hatch_Input) aMetaTileEntity).mRecipeMap = null;
+ mFermiumHatch = (GT_MetaTileEntity_Hatch_Input) aMetaTileEntity;
+ return true;
+ }
+ return false;
+ }
+
+ public Block getCasingBlock1() {
+ return ModBlocks.blockCasings5Misc;
+ }
+
+ public byte getCasingMeta1() {
+ return 15;
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ aNBT.setBoolean("mFluidMode", mFluidMode);
+ aNBT.setBoolean("doFermium", doFermium);
+ aNBT.setBoolean("doNeptunium", doNeptunium);
+ aNBT.setInteger("mMaxParallel", mMaxParallel);
+ super.saveNBTData(aNBT);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ if (!aNBT.hasKey(INPUT_SEPARATION_NBT_KEY)) {
+ inputSeparation = aNBT.getBoolean("mSeparateInputBusses");
+ }
+ if (!aNBT.hasKey(BATCH_MODE_NBT_KEY)) {
+ batchMode = aNBT.getBoolean("mBatchMode");
+ }
+ mFluidMode = aNBT.getBoolean("mFluidMode");
+ doFermium = aNBT.getBoolean("doFermium");
+ doNeptunium = aNBT.getBoolean("doNeptunium");
+ mMaxParallel = aNBT.getInteger("mMaxParallel");
+ }
+
+ @Override
+ public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection facing,
+ int aColorIndex, boolean aActive, boolean aRedstone) {
+ if (side == facing) {
+ if (aActive) return new ITexture[] { getCasingTexture(), TextureFactory.builder()
+ .addIcon(getActiveOverlay())
+ .extFacing()
+ .build() };
+ return new ITexture[] { getCasingTexture(), TextureFactory.builder()
+ .addIcon(getInactiveOverlay())
+ .extFacing()
+ .build() };
+ }
+ return new ITexture[] { getCasingTexture() };
+ }
+
+ private ITexture getCasingTexture() {
+ return Textures.BlockIcons.getCasingTextureForId(getCasingTextureId());
+ }
+
+ @SideOnly(Side.CLIENT)
+ private void renderForceField(double x, double y, double z, int side, double minU, double maxU, double minV,
+ double maxV) {
+ // spotless:off
+ Tessellator tes = Tessellator.instance;
+ switch (side) {
+ case 0 -> {
+ tes.addVertexWithUV(x + 3, y, z + 7, maxU, maxV);
+ tes.addVertexWithUV(x + 3, y + 4, z + 7, maxU, minV);
+ tes.addVertexWithUV(x - 3, y + 4, z + 7, minU, minV);
+ tes.addVertexWithUV(x - 3, y, z + 7, minU, maxV);
+ tes.addVertexWithUV(x - 3, y, z + 7, minU, maxV);
+ tes.addVertexWithUV(x - 3, y + 4, z + 7, minU, minV);
+ tes.addVertexWithUV(x + 3, y + 4, z + 7, maxU, minV);
+ tes.addVertexWithUV(x + 3, y, z + 7, maxU, maxV);
+ }
+ case 1 -> {
+ tes.addVertexWithUV(x + 7, y, z + 4, maxU, maxV);
+ tes.addVertexWithUV(x + 7, y + 4, z + 4, maxU, minV);
+ tes.addVertexWithUV(x + 7, y + 4, z - 4, minU, minV);
+ tes.addVertexWithUV(x + 7, y, z - 4, minU, maxV);
+ tes.addVertexWithUV(x + 7, y, z - 4, minU, maxV);
+ tes.addVertexWithUV(x + 7, y + 4, z - 4, minU, minV);
+ tes.addVertexWithUV(x + 7, y + 4, z + 4, maxU, minV);
+ tes.addVertexWithUV(x + 7, y, z + 4, maxU, maxV);
+ }
+ case 2 -> {
+ tes.addVertexWithUV(x + 3, y, z - 7, maxU, maxV);
+ tes.addVertexWithUV(x + 3, y + 4, z - 7, maxU, minV);
+ tes.addVertexWithUV(x - 3, y + 4, z - 7, minU, minV);
+ tes.addVertexWithUV(x - 3, y, z - 7, minU, maxV);
+ tes.addVertexWithUV(x - 3, y, z - 7, minU, maxV);
+ tes.addVertexWithUV(x - 3, y + 4, z - 7, minU, minV);
+ tes.addVertexWithUV(x + 3, y + 4, z - 7, maxU, minV);
+ tes.addVertexWithUV(x + 3, y, z - 7, maxU, maxV);
+ }
+ case 3 -> {
+ tes.addVertexWithUV(x - 7, y, z + 4, maxU, maxV);
+ tes.addVertexWithUV(x - 7, y + 4, z + 4, maxU, minV);
+ tes.addVertexWithUV(x - 7, y + 4, z - 4, minU, minV);
+ tes.addVertexWithUV(x - 7, y, z - 4, minU, maxV);
+ tes.addVertexWithUV(x - 7, y, z - 4, minU, maxV);
+ tes.addVertexWithUV(x - 7, y + 4, z - 4, minU, minV);
+ tes.addVertexWithUV(x - 7, y + 4, z + 4, maxU, minV);
+ tes.addVertexWithUV(x - 7, y, z + 4, maxU, maxV);
+ }
+ case 4 -> {
+ tes.addVertexWithUV(x - 3, y, z + 7, maxU, maxV);
+ tes.addVertexWithUV(x - 3, y + 4, z + 7, maxU, minV);
+ tes.addVertexWithUV(x - 7, y + 4, z + 4, minU, minV);
+ tes.addVertexWithUV(x - 7, y, z + 4, minU, maxV);
+ tes.addVertexWithUV(x - 7, y, z + 4, minU, maxV);
+ tes.addVertexWithUV(x - 7, y + 4, z + 4, minU, minV);
+ tes.addVertexWithUV(x - 3, y + 4, z + 7, maxU, minV);
+ tes.addVertexWithUV(x - 3, y, z + 7, maxU, maxV);
+ }
+ case 5 -> {
+ tes.addVertexWithUV(x - 3, y, z - 7, maxU, maxV);
+ tes.addVertexWithUV(x - 3, y + 4, z - 7, maxU, minV);
+ tes.addVertexWithUV(x - 7, y + 4, z - 4, minU, minV);
+ tes.addVertexWithUV(x - 7, y, z - 4, minU, maxV);
+ tes.addVertexWithUV(x - 7, y, z - 4, minU, maxV);
+ tes.addVertexWithUV(x - 7, y + 4, z - 4, minU, minV);
+ tes.addVertexWithUV(x - 3, y + 4, z - 7, maxU, minV);
+ tes.addVertexWithUV(x - 3, y, z - 7, maxU, maxV);
+ }
+ case 6 -> {
+ tes.addVertexWithUV(x + 3, y, z + 7, maxU, maxV);
+ tes.addVertexWithUV(x + 3, y + 4, z + 7, maxU, minV);
+ tes.addVertexWithUV(x + 7, y + 4, z + 4, minU, minV);
+ tes.addVertexWithUV(x + 7, y, z + 4, minU, maxV);
+ tes.addVertexWithUV(x + 7, y, z + 4, minU, maxV);
+ tes.addVertexWithUV(x + 7, y + 4, z + 4, minU, minV);
+ tes.addVertexWithUV(x + 3, y + 4, z + 7, maxU, minV);
+ tes.addVertexWithUV(x + 3, y, z + 7, maxU, maxV);
+ }
+ case 7 -> {
+ tes.addVertexWithUV(x + 3, y, z - 7, maxU, maxV);
+ tes.addVertexWithUV(x + 3, y + 4, z - 7, maxU, minV);
+ tes.addVertexWithUV(x + 7, y + 4, z - 4, minU, minV);
+ tes.addVertexWithUV(x + 7, y, z - 4, minU, maxV);
+ tes.addVertexWithUV(x + 7, y, z - 4, minU, maxV);
+ tes.addVertexWithUV(x + 7, y + 4, z - 4, minU, minV);
+ tes.addVertexWithUV(x + 3, y + 4, z - 7, maxU, minV);
+ tes.addVertexWithUV(x + 3, y, z - 7, maxU, maxV);
+ }
+ }
+ }
+
+ @SideOnly(Side.CLIENT)
+ @Override
+ public boolean renderInWorld(IBlockAccess aWorld, int x, int y, int z, Block block, RenderBlocks renderer) {
+ Tessellator tes = Tessellator.instance;
+ IIcon forceField = TexturesGtBlock.ForceField.getIcon();
+ if (getBaseMetaTileEntity().isActive()) {
+ double minU = forceField.getMinU();
+ double maxU = forceField.getMaxU();
+ double minV = forceField.getMinV();
+ double maxV = forceField.getMaxV();
+ double xBaseOffset = 3 * getExtendedFacing().getRelativeBackInWorld().offsetX;
+ double zBaseOffset = 3 * getExtendedFacing().getRelativeBackInWorld().offsetZ;
+ tes.setColorOpaque_F(1f, 1f, 1f);
+ tes.setBrightness(15728880);
+ //Center O: 0, 0 1 ------- 8
+ //Corner 1: 7, -2 / \
+ //Corner 2: 3, -6 2 / \ 7
+ //Corner 3: -2, -6 | |
+ //Corner 4: -6, -2 | O |
+ //Corner 5: -6, 3 | |
+ //Corner 6: -2, 7 3 \ / 6
+ //Corner 7: 3, 7 \ /
+ //Corner 8: 7, 3 4 ------- 5
+ renderForceField(x + xBaseOffset + 0.5, y, z + zBaseOffset + 0.5, 0, minU, maxU, minV, maxV);
+ renderForceField(x + xBaseOffset + 0.5, y, z + zBaseOffset + 0.5, 1, minU, maxU, minV, maxV);
+ renderForceField(x + xBaseOffset + 0.5, y, z + zBaseOffset + 0.5, 2, minU, maxU, minV, maxV);
+ renderForceField(x + xBaseOffset + 0.5, y, z + zBaseOffset + 0.5, 3, minU, maxU, minV, maxV);
+ renderForceField(x + xBaseOffset + 0.5, y, z + zBaseOffset + 0.5, 4, minU, maxU, minV, maxV);
+ renderForceField(x + xBaseOffset + 0.5, y, z + zBaseOffset + 0.5, 5, minU, maxU, minV, maxV);
+ renderForceField(x + xBaseOffset + 0.5, y, z + zBaseOffset + 0.5, 6, minU, maxU, minV, maxV);
+ renderForceField(x + xBaseOffset + 0.5, y, z + zBaseOffset + 0.5, 7, minU, maxU, minV, maxV);
+ }
+ // Needs to be false to render the controller
+ return false;
+ //spotless:on
+ }
+
+ @Override
+ public boolean supportsInputSeparation() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsBatchMode() {
+ return true;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_Refinery.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_Refinery.java
new file mode 100644
index 0000000000..8a6564858e
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_Refinery.java
@@ -0,0 +1,220 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+import static gregtech.api.util.GT_StructureUtility.filterByMTETier;
+
+import net.minecraft.item.ItemStack;
+
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.TAE;
+import gregtech.api.enums.Textures;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Muffler;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+
+public class GregtechMetaTileEntity_Refinery extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_Refinery>
+ implements ISurvivalConstructable {
+
+ private int mCasing;
+ private static IStructureDefinition<GregtechMetaTileEntity_Refinery> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_Refinery(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_Refinery(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Fuel Refinery";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Fission Fuel Processing Unit")
+ .addInfo("Refines fluorides and Uranium into nuclear fuel for the LFTR")
+ .addInfo("LFTR Fuel 2 and Fuel 3 have alternative, much more efficient recipes")
+ .addInfo("However, they require fission breeding outputs from the LFTR itself")
+ .addInfo("Only one Energy Hatch is allowed per Processing Unit")
+ .addInfo("All recipe times in this multi are very long, watch out!")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(3, 9, 3, false)
+ .addController("Bottom Center")
+ .addCasingInfoMin("Hastelloy-X Structural Block", 7, false)
+ .addCasingInfoMin("Incoloy-DS Fluid Containment Block", 5, false)
+ .addCasingInfoMin("Zeron-100 Reactor Shielding", 4, false)
+ .addCasingInfoMin("Hastelloy-N Sealant Blocks", 17, false)
+ .addInputHatch("Base platform", 1)
+ .addOutputHatch("Base platform", 1)
+ .addMufflerHatch("Base platform", 1)
+ .addMaintenanceHatch("Base platform", 1)
+ .addEnergyHatch("Base platform", 1)
+ .addStructureInfo("Muffler's Tier must be IV+")
+ .addStructureInfo("2-4x Input Hatches, 1-2x Output Hatches")
+ .addStructureInfo("1x Muffler, 1x Maintenance Hatch, 1x Energy Hatch")
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return Textures.BlockIcons.OVERLAY_FRONT_MULTI_SMELTER_ACTIVE;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return Textures.BlockIcons.OVERLAY_FRONT_MULTI_SMELTER;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return TAE.GTPP_INDEX(18);
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return GTPPRecipeMaps.fissionFuelProcessingRecipes;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic();
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 1;
+ }
+
+ @Override
+ public boolean addMufflerToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) {
+ if (aTileEntity == null) {
+ return false;
+ } else {
+ IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+ if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Muffler
+ && ((GT_MetaTileEntity_Hatch_Muffler) aMetaTileEntity).mTier >= 5) {
+ return addToMachineList(aTileEntity, aBaseCasingIndex);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_Refinery> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_Refinery>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { " ", " N ", " " }, { " N ", "NIN", " N " }, { " N ", "NIN", " N " },
+ { " N ", "NIN", " N " }, { " Z ", "ZIZ", " Z " }, { " N ", "NIN", " N " },
+ { "XXX", "XXX", "XXX" }, { "X~X", "XXX", "XXX" }, }))
+ .addElement(
+ 'X',
+ ofChain(
+ buildHatchAdder(GregtechMetaTileEntity_Refinery.class)
+ .atLeast(Energy, Maintenance, OutputHatch, OutputBus, InputHatch)
+ .casingIndex(TAE.GTPP_INDEX(18))
+ .dot(1)
+ .build(),
+ buildHatchAdder(GregtechMetaTileEntity_Refinery.class).atLeast(Muffler)
+ .adder(GregtechMetaTileEntity_Refinery::addMufflerToMachineList)
+ .hatchItemFilterAnd(t -> filterByMTETier(6, Integer.MAX_VALUE))
+ .casingIndex(TAE.GTPP_INDEX(18))
+ .dot(1)
+ .build(),
+ onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings2Misc, 2))))
+ .addElement('I', ofBlock(ModBlocks.blockCasings2Misc, 3))
+ .addElement('N', ofBlock(ModBlocks.blockCasings2Misc, 1))
+ .addElement('Z', ofBlock(ModBlocks.blockCasingsMisc, 13))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 1, 7, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 1, 7, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ if (checkPiece(mName, 1, 7, 0) && mCasing >= 7) {
+ if (this.mInputHatches.size() >= 2 && this.mInputHatches.size() <= 4
+ && this.mOutputHatches.size() >= 1
+ && this.mOutputHatches.size() <= 2
+ && this.mMufflerHatches.size() == 1
+ && this.mMaintenanceHatches.size() == 1
+ && this.mEnergyHatches.size() == 1) {
+ this.resetRecipeMapForAllInputHatches(this.getRecipeMap());
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(final ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiRefinery;
+ }
+
+ @Override
+ public int getDamageToComponent(final ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_Refinery(this.mName);
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_SolarTower.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_SolarTower.java
new file mode 100644
index 0000000000..0395ab5a01
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntity_SolarTower.java
@@ -0,0 +1,675 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.lazy;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import java.util.ArrayList;
+
+import net.minecraft.block.Block;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.world.World;
+import net.minecraftforge.common.util.ForgeDirection;
+import net.minecraftforge.fluids.Fluid;
+import net.minecraftforge.fluids.FluidStack;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits;
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.SoundResource;
+import gregtech.api.enums.TAE;
+import gregtech.api.enums.Textures;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.render.TextureFactory;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.material.MISC_MATERIALS;
+import gtPlusPlus.core.util.minecraft.FluidUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+import gtPlusPlus.xmod.gregtech.common.tileentities.misc.TileEntitySolarHeater;
+
+public class GregtechMetaTileEntity_SolarTower extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_SolarTower>
+ implements ISurvivalConstructable {
+
+ // 862
+ private static final int mCasingTextureID = TAE.getIndexFromPage(3, 9);
+ private int mHeatLevel = 0;
+ private int mCasing1;
+ private int mCasing2;
+ private int mCasing3;
+ private int mCasing4;
+
+ public ArrayList<TileEntitySolarHeater> mSolarHeaters = new ArrayList<>();
+
+ public GregtechMetaTileEntity_SolarTower(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_SolarTower(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_SolarTower(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Solar Tower";
+ }
+
+ @Override
+ protected final GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Contributing Green Energy towards the future")
+ .addInfo("Surround with rings of Solar Reflectors")
+ .addInfo("The Reflectors increase the internal heat value of the Tower (see below for formula)")
+ .addInfo("Each Reflector ring increases tier, the first ring is required for the Tower to work")
+ .addInfo("Input: " + MISC_MATERIALS.SOLAR_SALT_COLD.getLocalizedName())
+ .addInfo("Output: " + MISC_MATERIALS.SOLAR_SALT_HOT.getLocalizedName())
+ .addInfo("Every cycle (10 seconds), heat increases and all the Cold Solar Salt is heated")
+ .addInfo("Converting Cold to Hot Solar Salt reduces heat, equal to the amount converted")
+ .addInfo("This conversion only happens if heat >= 30000 and controller efficiency = 100%")
+ .addInfo("If there's more Cold Salt than heat, all the heat is used up and returns to 0")
+ .addInfo("The heat increase is most efficient at exactly half of maximum heat")
+ .addInfo("Minimum efficiency at 0 or 100000 heat, maximum efficiency at 50000")
+ .addInfo("Heat Efficiency formula: ( 7000 - [|currentHeat - 50000| ^ 0.8]) / 7000")
+ .addInfo("Heat gain per cycle: numberHeaters * heatEfficiency * (10 + bonus)")
+ .addInfo("Bonus: 1 ring = +1, 2 rings = +2, 3 rings = +4, 4 rings = +8, 5 rings = +16")
+ .addInfo("Total number of reflectors based on how many rings are built:")
+ .addInfo("1 ring = 36, 2 rings = 88, 3 rings = 156, 4 rings = 240, 5 rings = 340")
+ .addSeparator()
+ .beginVariableStructureBlock(15, 31, 28, 28, 15, 31, false)
+ .addController("Top Middle")
+ .addCasingInfoMin("Structural Solar Casing", 229, false)
+ .addCasingInfoMin("Thermally Insulated Casing", 60, false)
+ .addCasingInfoMin("Salt Containment Casing", 66, false)
+ .addCasingInfoMin("Thermal Containment Casing", 60, false)
+ .addInputHatch("Any 2 dot hint(min 1)", 2)
+ .addOutputHatch("Any 2 dot hint(min 1)", 2)
+ .addMaintenanceHatch("Any 2 dot hint", 2)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ private static final String STRUCTURE_PIECE_BASE = "base";
+ private static final String STRUCTURE_PIECE_TOWER = "tower";
+ private static final String STRUCTURE_PIECE_TOP = "top";
+
+ private static final String[] STRUCTURE_PIECE_SOLAR_HEATER_RING = { "ring1", "ring2", "ring3", "ring4", "ring5" };
+ private static final String SOLAR_HEATER_RING_1 = STRUCTURE_PIECE_SOLAR_HEATER_RING[0];
+ private static final String SOLAR_HEATER_RING_2 = STRUCTURE_PIECE_SOLAR_HEATER_RING[1];
+ private static final String SOLAR_HEATER_RING_3 = STRUCTURE_PIECE_SOLAR_HEATER_RING[2];
+ private static final String SOLAR_HEATER_RING_4 = STRUCTURE_PIECE_SOLAR_HEATER_RING[3];
+ private static final String SOLAR_HEATER_RING_5 = STRUCTURE_PIECE_SOLAR_HEATER_RING[4];
+
+ private static final ClassValue<IStructureDefinition<GregtechMetaTileEntity_SolarTower>> STRUCTURE_DEFINITION = new ClassValue<>() {
+
+ @Override
+ protected IStructureDefinition<GregtechMetaTileEntity_SolarTower> computeValue(Class<?> type) {
+ return StructureDefinition.<GregtechMetaTileEntity_SolarTower>builder()
+
+ // s = salt
+ // c = thermal containment
+ // i = thermal insulated
+ // t = solar structural
+ // h = hatch
+ // g = solar heater
+
+ .addShape(
+ STRUCTURE_PIECE_TOP,
+ (new String[][] { { " ", " ", " ~ ", " ", " " },
+ { " ", " s ", " sss ", " s ", " " },
+ { " c ", " ccc ", "ccscc", " ccc ", " c " },
+ { " c ", " ccc ", "ccscc", " ccc ", " c " },
+ { " c ", " ccc ", "ccscc", " ccc ", " c " },
+ { " c ", " ccc ", "ccscc", " ccc ", " c " },
+ { " c ", " ccc ", "ccscc", " ccc ", " c " }, }))
+ .addShape(
+ STRUCTURE_PIECE_TOWER,
+ (new String[][] { { " i ", "isi", " i " }, { " i ", "isi", " i " }, { " i ", "isi", " i " },
+ { " i ", "isi", " i " }, { " i ", "isi", " i " }, { " i ", "isi", " i " },
+ { " i ", "isi", " i " }, { " i ", "isi", " i " }, { " i ", "isi", " i " },
+ { " i ", "isi", " i " }, { " i ", "isi", " i " }, { " i ", "isi", " i " },
+ { " i ", "isi", " i " }, { " i ", "isi", " i " }, { " i ", "isi", " i " }, }))
+ .addShape(
+ STRUCTURE_PIECE_BASE,
+ (new String[][] {
+ { " ", " ", " t ", " ttt ", " ttstt ", " ttssstt ",
+ " ttstt ", " ttt ", " t ", " ", " " },
+ { " ", " ", " t ", " ttt ", " tssst ", " ttssstt ",
+ " tssst ", " ttt ", " t ", " ", " " },
+ { " ", " t ", " ttt ", " ttttt ", " ttssstt ", " tttsssttt ",
+ " ttssstt ", " ttttt ", " ttt ", " t ", " " },
+ { " ", " t ", " ttt ", " ttttt ", " ttssstt ", " tttsssttt ",
+ " ttssstt ", " ttttt ", " ttt ", " t ", " " },
+ { " hhh ", " ttttt ", " ttttttt ", " ttttttttt ", "htttsssttth", "htttsssttth",
+ "htttsssttth", " ttttttttt ", " ttttttt ", " ttttt ", " hhh " },
+ { " hhh ", " ttttt ", " ttttttt ", " ttttttttt ", "httttttttth", "httttttttth",
+ "httttttttth", " ttttttttt ", " ttttttt ", " ttttt ", " hhh " }, }))
+ .addShape(
+ SOLAR_HEATER_RING_1,
+ (new String[][] { { " ggggg ", " g g ", " g g ", " g g ",
+ " g g ", "g g", "g g", "g g", "g g",
+ "g g", " g g ", " g g ", " g g ", " g g ",
+ " ggggg ", } }))
+ .addShape(
+ SOLAR_HEATER_RING_2,
+ (new String[][] {
+ { " ggggggggg ", " g g ", " g g ", " g g ",
+ " g g ", "g g", "g g", "g g",
+ "g g", "g g", "g g", "g g",
+ "g g", "g g", " g g ", " g g ",
+ " g g ", " g g ", " ggggggggg ", } }))
+ .addShape(
+ SOLAR_HEATER_RING_3,
+ (new String[][] { { " ggggggggggggg ", " g g ", " g g ",
+ " g g ", " g g ", "g g",
+ "g g", "g g", "g g",
+ "g g", "g g", "g g",
+ "g g", "g g", "g g",
+ "g g", "g g", "g g",
+ " g g ", " g g ", " g g ",
+ " g g ", " ggggggggggggg ", } }))
+ .addShape(
+ SOLAR_HEATER_RING_4,
+ (new String[][] { { " ggggggggggggggggg ", " g g ",
+ " g g ", " g g ", " g g ",
+ "g g", "g g", "g g",
+ "g g", "g g", "g g",
+ "g g", "g g", "g g",
+ "g g", "g g", "g g",
+ "g g", "g g", "g g",
+ "g g", "g g", " g g ",
+ " g g ", " g g ", " g g ",
+ " ggggggggggggggggg ", } }))
+ .addShape(
+ SOLAR_HEATER_RING_5,
+ (new String[][] { { " ggggggggggggggggggggg ", " g g ",
+ " g g ", " g g ",
+ " g g ", "g g",
+ "g g", "g g",
+ "g g", "g g",
+ "g g", "g g",
+ "g g", "g g",
+ "g g", "g g",
+ "g g", "g g",
+ "g g", "g g",
+ "g g", "g g",
+ "g g", "g g",
+ "g g", "g g",
+ " g g ", " g g ",
+ " g g ", " g g ",
+ " ggggggggggggggggggggg ", } }))
+ .addElement(
+ 'g',
+ lazy(
+ t -> buildHatchAdder(GregtechMetaTileEntity_SolarTower.class)
+ .hatchClass(TileEntitySolarHeater.class)
+ .adder(GregtechMetaTileEntity_SolarTower::addSolarHeater)
+ // Use a positive casing index to make adder builder happy
+ .casingIndex(1)
+ .dot(1)
+ .continueIfSuccess()
+ .build()))
+ .addElement(
+ 't',
+ lazy(t -> onElementPass(x -> ++x.mCasing1, ofBlock(t.getCasingBlock(), t.getCasingMeta()))))
+ .addElement(
+ 'i',
+ lazy(t -> onElementPass(x -> ++x.mCasing2, ofBlock(t.getCasingBlock(), t.getCasingMeta2()))))
+ .addElement(
+ 's',
+ lazy(t -> onElementPass(x -> ++x.mCasing3, ofBlock(t.getCasingBlock(), t.getCasingMeta3()))))
+ .addElement(
+ 'c',
+ lazy(t -> onElementPass(x -> ++x.mCasing4, ofBlock(t.getCasingBlock2(), t.getCasingMeta4()))))
+ .addElement(
+ 'h',
+ lazy(
+ t -> buildHatchAdder(GregtechMetaTileEntity_SolarTower.class)
+ .atLeast(InputHatch, OutputHatch, Maintenance)
+ .casingIndex(t.getCasingTextureIndex())
+ .dot(2)
+ .buildAndChain(
+ onElementPass(x -> ++x.mCasing1, ofBlock(t.getCasingBlock(), t.getCasingMeta())))))
+ .build();
+ }
+ };
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ resetSolarHeaters();
+ this.mMaintenanceHatches.clear();
+ this.mInputHatches.clear();
+ this.mOutputHatches.clear();
+ mCasing1 = 0;
+ mCasing2 = 0;
+ mCasing3 = 0;
+ mCasing4 = 0;
+
+ boolean aStructureTop = checkPiece(STRUCTURE_PIECE_TOP, 2, 2, 0);
+ log("Top Check: " + aStructureTop);
+ boolean aStructureTower = checkPiece(STRUCTURE_PIECE_TOWER, 1, 1, -7);
+ log("Tower Check: " + aStructureTower);
+ boolean aStructureBase = checkPiece(STRUCTURE_PIECE_BASE, 5, 5, -22);
+ log("Base Check: " + aStructureBase);
+ boolean aCasingCount1 = mCasing1 >= 229;
+ boolean aCasingCount2 = mCasing2 == 60;
+ boolean aCasingCount3 = mCasing3 == 66;
+ boolean aCasingCount4 = mCasing4 == 60;
+ boolean aAllStructure = aStructureTop && aStructureTower && aStructureBase;
+ boolean aAllCasings = aCasingCount1 && aCasingCount2 && aCasingCount3 && aCasingCount4;
+ if (!aAllCasings || !aAllStructure
+ || mMaintenanceHatches.size() != 1
+ || mInputHatches.size() < 1
+ || mOutputHatches.size() < 1) {
+ log(
+ "Bad Hatches - Solar Heaters: " + mSolarHeaters.size()
+ + ", Maint: "
+ + mMaintenanceHatches.size()
+ + ", Input Hatches: "
+ + mInputHatches.size()
+ + ", Output Hatches: "
+ + mOutputHatches.size()
+ + ", Top: "
+ + aStructureTop
+ + ", Tower: "
+ + aStructureTower
+ + ", Base: "
+ + aStructureBase
+ + ", Casing Count: "
+ + aCasingCount1
+ + " | Found: "
+ + mCasing1
+ + ", Casing Count: "
+ + aCasingCount2
+ + " | Found: "
+ + mCasing2
+ + ", Casing Count: "
+ + aCasingCount3
+ + " | Found: "
+ + mCasing3
+ + ", Casing Count: "
+ + aCasingCount4
+ + " | Found: "
+ + mCasing4);
+ return false;
+ }
+ log(
+ "Built " + this.getLocalName()
+ + " with "
+ + mCasing1
+ + " Structural Solar casings, "
+ + mCasing2
+ + " Thermally Insulated casings, "
+ + mCasing3
+ + " Salt Containment casings, "
+ + mCasing4
+ + " Thermal Containment casings.");
+ return aAllCasings && aAllStructure;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ // Tower
+ buildPiece(STRUCTURE_PIECE_TOP, stackSize, hintsOnly, 2, 2, 0);
+ buildPiece(STRUCTURE_PIECE_TOWER, stackSize, hintsOnly, 1, 1, -7);
+ buildPiece(STRUCTURE_PIECE_BASE, stackSize, hintsOnly, 5, 5, -22);
+
+ // Solar Heaters
+ if (stackSize.stackSize >= 1) {
+ buildPiece(SOLAR_HEATER_RING_1, stackSize, hintsOnly, 7, 7, -27);
+ if (stackSize.stackSize >= 2) {
+ buildPiece(SOLAR_HEATER_RING_2, stackSize, hintsOnly, 9, 9, -27);
+ if (stackSize.stackSize >= 3) {
+ buildPiece(SOLAR_HEATER_RING_3, stackSize, hintsOnly, 11, 11, -27);
+ if (stackSize.stackSize >= 4) {
+ buildPiece(SOLAR_HEATER_RING_4, stackSize, hintsOnly, 13, 13, -27);
+ if (stackSize.stackSize >= 5) {
+ buildPiece(SOLAR_HEATER_RING_5, stackSize, hintsOnly, 15, 15, -27);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ int built;
+ int realBudget = elementBudget >= 200 ? elementBudget : Math.min(200, elementBudget * 2);
+ // Tower
+ built = survivialBuildPiece(STRUCTURE_PIECE_TOP, stackSize, 2, 2, 0, realBudget, env, false, true);
+ if (built >= 0) return built;
+ built = survivialBuildPiece(STRUCTURE_PIECE_TOWER, stackSize, 1, 1, -7, realBudget, env, false, true);
+ if (built >= 0) return built;
+ built = survivialBuildPiece(STRUCTURE_PIECE_BASE, stackSize, 5, 5, -22, realBudget, env, false, true);
+ if (built >= 0) return built;
+
+ // Solar Heaters
+ if (stackSize.stackSize < 1) return -1;
+ built = survivialBuildPiece(SOLAR_HEATER_RING_1, stackSize, 7, 7, -27, realBudget, env, false, true);
+ if (built >= 0) return built;
+ if (stackSize.stackSize < 2) return -1;
+ built = survivialBuildPiece(SOLAR_HEATER_RING_2, stackSize, 9, 9, -27, realBudget, env, false, true);
+ if (built >= 0) return built;
+ if (stackSize.stackSize < 3) return -1;
+ built = survivialBuildPiece(SOLAR_HEATER_RING_3, stackSize, 11, 11, -27, realBudget, env, false, true);
+ if (built >= 0) return built;
+ if (stackSize.stackSize < 4) return -1;
+ built = survivialBuildPiece(SOLAR_HEATER_RING_4, stackSize, 13, 13, -27, realBudget, env, false, true);
+ if (built >= 0) return built;
+ if (stackSize.stackSize < 5) return -1;
+ return survivialBuildPiece(SOLAR_HEATER_RING_5, stackSize, 15, 15, -27, realBudget, env, false, true);
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_SolarTower> getStructureDefinition() {
+ return STRUCTURE_DEFINITION.get(getClass());
+ }
+
+ @Override
+ protected SoundResource getProcessStartSound() {
+ return SoundResource.IC2_MACHINES_MAGNETIZER_LOOP;
+ }
+
+ @Override
+ public ITexture[] getTexture(final IGregTechTileEntity aBaseMetaTileEntity, final ForgeDirection side,
+ final ForgeDirection facing, final int aColorIndex, final boolean aActive, final boolean aRedstone) {
+ if (side == ForgeDirection.DOWN || side == ForgeDirection.UP) {
+ if (aActive) return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(TAE.GTPP_INDEX(12)),
+ TextureFactory.builder()
+ .addIcon(TexturesGtBlock.Overlay_Machine_Controller_Default_Active)
+ .extFacing()
+ .build() };
+ return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(TAE.GTPP_INDEX(12)),
+ TextureFactory.builder()
+ .addIcon(TexturesGtBlock.Overlay_Machine_Controller_Default)
+ .extFacing()
+ .build() };
+ }
+ return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(TAE.GTPP_INDEX(12)) };
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ // Only for visual
+ return GTPPRecipeMaps.solarTowerRecipes;
+ }
+
+ private int getHeaterTier() {
+ int aSolarHeaterCounter = this.mSolarHeaters.size();
+ if (aSolarHeaterCounter > 0) {
+ if (aSolarHeaterCounter == 36) {
+ return 1;
+ } else if (aSolarHeaterCounter == 88) {
+ return 2;
+ } else if (aSolarHeaterCounter == 156) {
+ return 4;
+ } else if (aSolarHeaterCounter == 240) {
+ return 8;
+ } else if (aSolarHeaterCounter == 340) {
+ return 16;
+ }
+ }
+ return 0;
+ }
+
+ private int getHeaterCountForTier(int aTier) {
+ return switch (aTier) {
+ case 1 -> 36;
+ case 2 -> 88;
+ case 4 -> 156;
+ case 8 -> 240;
+ case 16 -> 340;
+ default -> 0;
+ };
+ }
+
+ public boolean getConnectedSolarReflectors() {
+
+ resetSolarHeaters();
+ int aRing = 1;
+
+ if (this.mSolarHeaters.size() < 36) {
+ // 15x15
+ boolean aRing1 = checkPiece(SOLAR_HEATER_RING_1, 7, 7, -27);
+ if (aRing1) {
+ // log("Found Ring: "+(aRing++)+", Total: "+this.mSolarHeaters.size());
+ }
+ }
+ if (this.mSolarHeaters.size() < 88) {
+ // 17x17
+ boolean aRing2 = checkPiece(SOLAR_HEATER_RING_2, 9, 9, -27);
+ if (aRing2) {
+ // log("Found Ring: "+(aRing++)+", Total: "+this.mSolarHeaters.size());
+ }
+ }
+ if (this.mSolarHeaters.size() < 156) {
+ // 19x19
+ boolean aRing3 = checkPiece(SOLAR_HEATER_RING_3, 11, 11, -27);
+ if (aRing3) {
+ // log("Found Ring: "+(aRing++)+", Total: "+this.mSolarHeaters.size());
+ }
+ }
+ if (this.mSolarHeaters.size() < 240) {
+ // 21x21
+ boolean aRing4 = checkPiece(SOLAR_HEATER_RING_4, 13, 13, -27);
+ if (aRing4) {
+ // log("Found Ring: "+(aRing++)+", Total: "+this.mSolarHeaters.size());
+ }
+ }
+ if (this.mSolarHeaters.size() < 340) {
+ // 23x23
+ boolean aRing5 = checkPiece(SOLAR_HEATER_RING_5, 15, 15, -27);
+ if (aRing5) {
+ // log("Found Ring: "+(aRing++)+", Total: "+this.mSolarHeaters.size());
+ }
+ }
+ return mSolarHeaters.size() > 0;
+ }
+
+ private boolean addSolarHeater(IGregTechTileEntity aTileEntity, int a) {
+ if (aTileEntity == null) {
+ return false;
+ } else {
+ IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+ if (aMetaTileEntity instanceof TileEntitySolarHeater mTile) {
+ if (!mTile.hasSolarTower() && mTile.canSeeSky()) {
+ // Logger.INFO("Found Solar Reflector, Injecting Data.");
+ mTile.setSolarTower(this);
+ return this.mSolarHeaters.add(mTile);
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected IAlignmentLimits getInitialAlignmentLimits() {
+ return (d, r, f) -> d == ForgeDirection.UP;
+ }
+
+ private Fluid mColdSalt = null;
+ private Fluid mHotSalt = null;
+
+ @Override
+ public @NotNull CheckRecipeResult checkProcessing() {
+ this.mEfficiencyIncrease = 100;
+ this.mMaxProgresstime = 200;
+
+ if (this.mSolarHeaters.isEmpty() || this.mSolarHeaters.size() < 340
+ || this.getTotalRuntimeInTicks() % 200 == 0) {
+ getConnectedSolarReflectors();
+ }
+
+ int aTier = getHeaterTier();
+ int aHeaters = getHeaterCountForTier(aTier);
+
+ // Original formula was (-Math.pow(this.mHeatLevel - 50000, 0.8) + 7000) / 7000
+ // However, negative numbers to the power of a non-integer result in NaN, by default
+ // Max efficiency is 1, at mHeatLevel = 50000, and it lowers at the same rate if going above or below this heat
+ // Min efficiency is 0.179, at mHeatLevel = 0 or 100000
+ double aEfficiency = (-Math.pow(Math.abs(this.mHeatLevel - 50000), 0.8) + 7000) / 7000;
+
+ World w = this.getBaseMetaTileEntity()
+ .getWorld();
+
+ // Manage Heat every 10s
+ // Add Heat First, if sources available and it's daytime, heat gain is halved if raining
+ if (w != null) {
+ if (aHeaters > 0 && w.isDaytime()) {
+ if (w.isRaining() && this.getBaseMetaTileEntity()
+ .getBiome().rainfall > 0.0F) {
+ this.mHeatLevel += GT_Utility.safeInt((long) ((aHeaters / 2) * aEfficiency * (10 + aTier)));
+ } else {
+ this.mHeatLevel += GT_Utility.safeInt((long) (aHeaters * aEfficiency * (10 + aTier)));
+ }
+ }
+
+ // Remove Heat, based on time of day
+ if (mHeatLevel > 0) {
+ if (mHeatLevel > 100000) {
+ this.mHeatLevel = 100000;
+ } else {
+ this.mHeatLevel -= 10;
+ }
+ }
+ }
+
+ if (this.mEfficiency == this.getMaxEfficiency(null) && this.mHeatLevel >= 30000) {
+ if (mColdSalt == null) {
+ mColdSalt = MISC_MATERIALS.SOLAR_SALT_COLD.getFluid();
+ }
+ if (mHotSalt == null) {
+ mHotSalt = MISC_MATERIALS.SOLAR_SALT_HOT.getFluid();
+ }
+ ArrayList<FluidStack> aFluids = this.getStoredFluids();
+ for (FluidStack aFluid : aFluids) {
+ if (aFluid.getFluid()
+ .equals(mColdSalt)) {
+ int aFluidAmount = Math.min(aFluid.amount, this.mHeatLevel);
+
+ this.mHeatLevel -= aFluidAmount;
+ this.depleteInput(FluidUtils.getFluidStack(mColdSalt, aFluidAmount));
+ this.addOutput(FluidUtils.getFluidStack(mHotSalt, aFluidAmount));
+ this.mHeatLevel = Math.max(this.mHeatLevel, 0);
+
+ break;
+ }
+ }
+ }
+
+ return CheckRecipeResultRegistry.GENERATING;
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 1;
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerTick(final ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ public Block getCasingBlock() {
+ return ModBlocks.blockSpecialMultiCasings;
+ }
+
+ public Block getCasingBlock2() {
+ return ModBlocks.blockCasings2Misc;
+ }
+
+ public byte getCasingMeta() {
+ return 6;
+ }
+
+ public byte getCasingMeta2() {
+ return 8;
+ }
+
+ public byte getCasingMeta3() {
+ return 7;
+ }
+
+ public byte getCasingMeta4() {
+ return 11;
+ }
+
+ public byte getCasingTextureIndex() {
+ return (byte) mCasingTextureID;
+ }
+
+ @Override
+ public void onModeChangeByScrewdriver(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {}
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ super.saveNBTData(aNBT);
+ aNBT.setInteger("mHeatLevel", mHeatLevel);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ mHeatLevel = aNBT.getInteger("mHeatLevel");
+ }
+
+ @Override
+ public void onRemoval() {
+ resetSolarHeaters();
+ super.onRemoval();
+ }
+
+ private void resetSolarHeaters() {
+ for (TileEntitySolarHeater aTile : this.mSolarHeaters) {
+ aTile.clearSolarTower();
+ }
+ this.mSolarHeaters.clear();
+ }
+
+ @Override
+ public String[] getExtraInfoData() {
+ return new String[] { "Internal Heat Level: " + this.mHeatLevel,
+ "Connected Solar Reflectors: " + this.mSolarHeaters.size() };
+ }
+
+ @Override
+ public boolean doesBindPlayerInventory() {
+ return false;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/algae/GregtechMTE_AlgaePondBase.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/algae/GregtechMTE_AlgaePondBase.java
new file mode 100644
index 0000000000..8a3442b5e7
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/algae/GregtechMTE_AlgaePondBase.java
@@ -0,0 +1,376 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production.algae;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import java.util.stream.Stream;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.minecraft.block.Block;
+import net.minecraft.init.Blocks;
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.fluids.FluidStack;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits;
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.GregTech_API;
+import gregtech.api.enums.SoundResource;
+import gregtech.api.enums.TAE;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.recipe.check.SimpleCheckRecipeResult;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.GT_StreamUtil;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.api.objects.Logger;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.item.chemistry.AgriculturalChem;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.minecraft.FluidUtils;
+import gtPlusPlus.core.util.minecraft.ItemUtils;
+import gtPlusPlus.core.util.reflect.ReflectionUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+import gtPlusPlus.xmod.gregtech.loaders.recipe.RecipeLoader_AlgaeFarm;
+import ic2.core.init.BlocksItems;
+import ic2.core.init.InternalName;
+
+public class GregtechMTE_AlgaePondBase extends GregtechMeta_MultiBlockBase<GregtechMTE_AlgaePondBase>
+ implements ISurvivalConstructable {
+
+ private int mLevel = -1;
+ private int mCasing;
+ private static IStructureDefinition<GregtechMTE_AlgaePondBase> STRUCTURE_DEFINITION = null;
+ private int checkMeta;
+ private int minTierOfHatch;
+ private static final Class<?> cofhWater;
+
+ static {
+ cofhWater = ReflectionUtils.getClass("cofh.asmhooks.block.BlockWater");
+ }
+
+ public GregtechMTE_AlgaePondBase(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMTE_AlgaePondBase(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMTE_AlgaePondBase(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Algae Pond";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Grows Algae!")
+ .addInfo("Controller Block for the Algae Farm")
+ .addInfo("Provide compost to boost production by one tier")
+ .addInfo("Does not require power or maintenance")
+ .addInfo("All Machine Casings must be the same tier, this dictates machine speed.")
+ .addInfo("All Buses/Hatches must, at least, match the tier of the Casings")
+ .addInfo("Fill Input Hatch with Water to fill the inside of the multiblock.")
+ .addPollutionAmount(getPollutionPerSecond(null))
+ .addSeparator()
+ .beginStructureBlock(9, 3, 9, true)
+ .addController("Front Center")
+ .addCasingInfoMin("Machine Casings", 64, true)
+ .addCasingInfoMin("Sterile Farm Casings", 64, false)
+ .addInputBus("Any Casing", 1)
+ .addOutputBus("Any Casing", 1)
+ .addInputHatch("Any Casing", 1)
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ public void setMeta(int meta) {
+ checkMeta = meta;
+ }
+
+ public int getMeta() {
+ return checkMeta;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMTE_AlgaePondBase> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMTE_AlgaePondBase>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] {
+ { "XXXXXXXXX", "X X", "X X", "X X", "X X", "X X", "X X",
+ "X X", "XXXXXXXXX" },
+ { "XXXXXXXXX", "X X", "X X", "X X", "X X", "X X", "X X",
+ "X X", "XXXXXXXXX" },
+ { "CCCC~CCCC", "CCCCCCCCC", "CCCCCCCCC", "CCCCCCCCC", "CCCCCCCCC", "CCCCCCCCC", "CCCCCCCCC",
+ "CCCCCCCCC", "CCCCCCCCC" }, }))
+ .addElement(
+ 'C',
+ ofChain(
+ buildHatchAdder(GregtechMTE_AlgaePondBase.class).atLeast(InputHatch, InputBus, OutputBus)
+ .casingIndex(TAE.getIndexFromPage(1, 15))
+ .dot(1)
+ .build(),
+ onElementPass(
+ x -> ++x.mCasing,
+ addTieredBlock(
+ GregTech_API.sBlockCasings1,
+ GregtechMTE_AlgaePondBase::setMeta,
+ GregtechMTE_AlgaePondBase::getMeta,
+ 10))))
+ .addElement('X', ofBlock(ModBlocks.blockCasings2Misc, 15))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 4, 2, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 4, 2, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ mLevel = 0;
+ checkMeta = 0;
+ minTierOfHatch = 100;
+ if (checkPiece(mName, 4, 2, 0) && mCasing >= 64 && checkMeta > 0) {
+ mLevel = checkMeta - 1;
+ return mLevel <= minTierOfHatch;
+ }
+ return false;
+ }
+
+ @Override
+ protected IAlignmentLimits getInitialAlignmentLimits() {
+ return (d, r, f) -> d.offsetY == 0 && r.isNotRotated() && !f.isVerticallyFliped();
+ }
+
+ @Override
+ protected SoundResource getProcessStartSound() {
+ return SoundResource.IC2_MACHINES_ELECTROFURNACE_LOOP;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Default;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ int aID = TAE.getIndexFromPage(1, 15);
+ if (mLevel > -1) {
+ aID = mLevel;
+ }
+ return aID;
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 2;
+ }
+
+ public boolean checkForWater() {
+
+ // Get Facing direction
+ IGregTechTileEntity aBaseMetaTileEntity = this.getBaseMetaTileEntity();
+ int mDirectionX = aBaseMetaTileEntity.getBackFacing().offsetX;
+ int mCurrentDirectionX;
+ int mCurrentDirectionZ;
+ int mOffsetX_Lower = 0;
+ int mOffsetX_Upper = 0;
+ int mOffsetZ_Lower = 0;
+ int mOffsetZ_Upper = 0;
+
+ mCurrentDirectionX = 4;
+ mCurrentDirectionZ = 4;
+
+ mOffsetX_Lower = -4;
+ mOffsetX_Upper = 4;
+ mOffsetZ_Lower = -4;
+ mOffsetZ_Upper = 4;
+
+ // if (aBaseMetaTileEntity.fac)
+
+ final int xDir = aBaseMetaTileEntity.getBackFacing().offsetX * mCurrentDirectionX;
+ final int zDir = aBaseMetaTileEntity.getBackFacing().offsetZ * mCurrentDirectionZ;
+
+ int tAmount = 0;
+ for (int i = mOffsetX_Lower + 1; i <= mOffsetX_Upper - 1; ++i) {
+ for (int j = mOffsetZ_Lower + 1; j <= mOffsetZ_Upper - 1; ++j) {
+ for (int h = 0; h < 2; h++) {
+ Block tBlock = aBaseMetaTileEntity.getBlockOffset(xDir + i, h, zDir + j);
+ byte tMeta = aBaseMetaTileEntity.getMetaIDOffset(xDir + i, h, zDir + j);
+ if (isNotStaticWater(tBlock, tMeta)) {
+ if (this.getStoredFluids() != null) {
+ for (FluidStack stored : this.getStoredFluids()) {
+ if (stored.isFluidEqual(FluidUtils.getFluidStack("water", 1))) {
+ if (stored.amount >= 1000) {
+ // Utils.LOG_WARNING("Going to try swap an air block for water from inut bus.");
+ stored.amount -= 1000;
+ Block fluidUsed = Blocks.water;
+ aBaseMetaTileEntity.getWorld()
+ .setBlock(
+ aBaseMetaTileEntity.getXCoord() + xDir + i,
+ aBaseMetaTileEntity.getYCoord() + h,
+ aBaseMetaTileEntity.getZCoord() + zDir + j,
+ fluidUsed);
+ }
+ }
+ }
+ }
+ }
+ tBlock = aBaseMetaTileEntity.getBlockOffset(xDir + i, h, zDir + j);
+ if (tBlock == Blocks.water || tBlock == Blocks.flowing_water) {
+ ++tAmount;
+ // Logger.INFO("Found Water");
+ }
+ }
+ }
+ }
+
+ boolean isValidWater = tAmount >= 49;
+
+ if (isValidWater) {
+ Logger.INFO("Filled structure.");
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private boolean isNotStaticWater(Block block, byte meta) {
+ return block == Blocks.air || block == Blocks.flowing_water
+ || block == BlocksItems.getFluidBlock(InternalName.fluidDistilledWater)
+ || (cofhWater != null && cofhWater.isAssignableFrom(block.getClass()) && meta != 0);
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerSecond(final ItemStack aStack) {
+ return CORE.ConfigSwitches.pollutionPerSecondMultiAlgaePond;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {
+ super.onPostTick(aBaseMetaTileEntity, aTick);
+ }
+
+ @Override
+ public void onPreTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {
+ super.onPreTick(aBaseMetaTileEntity, aTick);
+ this.fixAllMaintenanceIssue();
+ // Silly Client Syncing
+ if (aBaseMetaTileEntity.isClientSide()) {
+ this.mLevel = getCasingTier();
+ }
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic() {
+
+ @Nonnull
+ @Override
+ protected Stream<GT_Recipe> findRecipeMatches(@Nullable RecipeMap<?> map) {
+ return GT_StreamUtil
+ .ofNullable(RecipeLoader_AlgaeFarm.getTieredRecipeFromCache(mLevel, isUsingCompost(inputItems)));
+ }
+
+ @NotNull
+ @Override
+ protected CheckRecipeResult validateRecipe(@NotNull GT_Recipe recipe) {
+ if (!checkForWater()) {
+ return SimpleCheckRecipeResult.ofFailure("no_water");
+ }
+ return CheckRecipeResultRegistry.SUCCESSFUL;
+ }
+ }.setEuModifier(0F)
+ .setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ private boolean isUsingCompost(ItemStack[] aItemInputs) {
+ ItemStack aCompost = ItemUtils.getSimpleStack(AgriculturalChem.mCompost, 1);
+ for (ItemStack i : aItemInputs) {
+ if (GT_Utility.areStacksEqual(aCompost, i)) {
+ if (i.stackSize >= RecipeLoader_AlgaeFarm.compostForTier(mLevel)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private int getCasingTier() {
+ if (this.getBaseMetaTileEntity()
+ .getWorld() == null) {
+ return 0;
+ }
+ try {
+ Block aInitStructureCheck;
+ int aInitStructureCheckMeta;
+ IGregTechTileEntity aBaseMetaTileEntity = this.getBaseMetaTileEntity();
+ int xDir = aBaseMetaTileEntity.getBackFacing().offsetX;
+ int zDir = aBaseMetaTileEntity.getBackFacing().offsetZ;
+ aInitStructureCheck = aBaseMetaTileEntity.getBlockOffset(xDir, -1, zDir);
+ aInitStructureCheckMeta = aBaseMetaTileEntity.getMetaIDOffset(xDir, -1, zDir);
+ if (aInitStructureCheck == GregTech_API.sBlockCasings1) {
+ return aInitStructureCheckMeta;
+ }
+ return 0;
+ } catch (Throwable t) {
+ t.printStackTrace();
+ return 0;
+ }
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/chemplant/GregtechMTE_ChemicalPlant.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/chemplant/GregtechMTE_ChemicalPlant.java
new file mode 100644
index 0000000000..30d2f75457
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/chemplant/GregtechMTE_ChemicalPlant.java
@@ -0,0 +1,676 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production.chemplant;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.withChannel;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+import static gregtech.api.util.GT_StructureUtility.filterByMTETier;
+import static gregtech.api.util.GT_StructureUtility.ofCoil;
+import static gregtech.api.util.GT_Utility.filterValidMTEs;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.minecraft.block.Block;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.world.World;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.StructureLibAPI;
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.AutoPlaceEnvironment;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.IStructureElement;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+import com.gtnewhorizon.structurelib.structure.StructureUtility;
+
+import gregtech.api.GregTech_API;
+import gregtech.api.enums.HeatingCoilLevel;
+import gregtech.api.enums.SoundResource;
+import gregtech.api.interfaces.IIconContainer;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.metatileentity.GregTechTileClientEvents;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Energy;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_InputBus;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Maintenance;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_OutputBus;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_TieredMachineBlock;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.recipe.check.SimpleCheckRecipeResult;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.GT_Utility;
+import gregtech.common.tileentities.machines.IDualInputHatch;
+import gtPlusPlus.api.objects.data.AutoMap;
+import gtPlusPlus.api.objects.data.Triplet;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.item.chemistry.general.ItemGenericChemBase;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.recipe.common.CI;
+import gtPlusPlus.core.util.math.MathUtils;
+import gtPlusPlus.core.util.minecraft.ItemUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.nbthandlers.GT_MetaTileEntity_Hatch_Catalysts;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregtechMTE_ChemicalPlant extends GregtechMeta_MultiBlockBase<GregtechMTE_ChemicalPlant>
+ implements ISurvivalConstructable {
+
+ private int mSolidCasingTier = 0;
+ private int mMachineCasingTier = 0;
+ private int mPipeCasingTier = 0;
+ private int mCoilTier = 0;
+ private HeatingCoilLevel checkCoil;
+ private int[] checkCasing = new int[8];
+ private int checkMachine;
+ private int checkPipe;
+ private int maxTierOfHatch;
+ private int mCasing;
+ private static IStructureDefinition<GregtechMTE_ChemicalPlant> STRUCTURE_DEFINITION = null;
+
+ private final ArrayList<GT_MetaTileEntity_Hatch_Catalysts> mCatalystBuses = new ArrayList<>();
+
+ private static final HashMap<Integer, Triplet<Block, Integer, Integer>> mTieredBlockRegistry = new HashMap<>();
+
+ public GregtechMTE_ChemicalPlant(final int aID, final String aName, final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMTE_ChemicalPlant(final String aName) {
+ super(aName);
+ }
+
+ public static boolean registerMachineCasingForTier(int aTier, Block aBlock, int aMeta, int aCasingTextureID) {
+ Triplet<Block, Integer, Integer> aCasingData = new Triplet<>(aBlock, aMeta, aCasingTextureID);
+ if (mTieredBlockRegistry.containsKey(aTier)) {
+ CORE.crash(
+ "Tried to register a Machine casing for tier " + aTier
+ + " to the Chemical Plant, however this tier already contains one.");
+ }
+ mTieredBlockRegistry.put(aTier, aCasingData);
+ return true;
+ }
+
+ private static int getCasingTextureIdForTier(int aTier) {
+ if (!mTieredBlockRegistry.containsKey(aTier)) {
+ return 10;
+ }
+ int aCasingID = mTieredBlockRegistry.get(aTier)
+ .getValue_3();
+ // Logger.INFO("Found casing texture ID "+aCasingID+" for tier "+aTier);
+ return aCasingID;
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMTE_ChemicalPlant(this.mName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Chemical Plant";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the Chemical Plant")
+ .addInfo("Heavy Industry, now right at your doorstep!")
+ .addInfo("Please read the user manual for more information on construction and usage")
+ .addSeparator()
+ .addController("Bottom Center")
+ .addStructureHint("Catalyst Housing", 1)
+ .addInputBus("Bottom Casing", 1)
+ .addOutputBus("Bottom Casing", 1)
+ .addInputHatch("Bottom Casing", 1)
+ .addOutputHatch("Bottom Casing", 1)
+ .addEnergyHatch("Bottom Casing", 1)
+ .addMaintenanceHatch("Bottom Casing", 1)
+ .addSubChannelUsage("casing", "metal machine casing")
+ .addSubChannelUsage("machine", "tier machine casing")
+ .addSubChannelUsage("coil", "heating coil blocks")
+ .addSubChannelUsage("pipe", "pipe casing blocks")
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ public void setMachineMeta(int meta) {
+ checkMachine = meta;
+ }
+
+ public int getMachineMeta() {
+ return checkMachine;
+ }
+
+ public void setPipeMeta(int meta) {
+ checkPipe = meta;
+ }
+
+ public int getPipeMeta() {
+ return checkPipe;
+ }
+
+ public void setCoilMeta(HeatingCoilLevel meta) {
+ checkCoil = meta;
+ }
+
+ public HeatingCoilLevel getCoilMeta() {
+ return checkCoil;
+ }
+
+ @Override
+ public IStructureDefinition<GregtechMTE_ChemicalPlant> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ IStructureElement<GregtechMTE_ChemicalPlant> allCasingsElement = withChannel(
+ "casing",
+ ofChain(
+ IntStream.range(0, 8)
+ .mapToObj(GregtechMTE_ChemicalPlant::ofSolidCasing)
+ .collect(Collectors.toList())));
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMTE_ChemicalPlant>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] {
+ { "XXXXXXX", "XXXXXXX", "XXXXXXX", "XXXXXXX", "XXXXXXX", "XXXXXXX", "XXXXXXX" },
+ { "X X", " MMMMM ", " MHHHM ", " MHHHM ", " MHHHM ", " MMMMM ", "X X" },
+ { "X X", " ", " PPP ", " PPP ", " PPP ", " ", "X X" },
+ { "X X", " ", " HHH ", " HHH ", " HHH ", " ", "X X" },
+ { "X X", " ", " PPP ", " PPP ", " PPP ", " ", "X X" },
+ { "X X", " MMMMM ", " MHHHM ", " MHHHM ", " MHHHM ", " MMMMM ", "X X" },
+ { "CCC~CCC", "CMMMMMC", "CMMMMMC", "CMMMMMC", "CMMMMMC", "CMMMMMC", "CCCCCCC" }, }))
+ .addElement(
+ 'C',
+ ofChain(
+ buildHatchAdder(GregtechMTE_ChemicalPlant.class).atLeast(Maintenance)
+ .casingIndex(getCasingTextureID())
+ .dot(1)
+ .build(),
+ buildHatchAdder(GregtechMTE_ChemicalPlant.class)
+ .atLeast(InputHatch, OutputHatch, InputBus, OutputBus)
+ .adder(GregtechMTE_ChemicalPlant::addChemicalPlantList)
+ .hatchItemFilterAnd(
+ (t, s) -> filterByMTETier(
+ Integer.MIN_VALUE,
+ s.stackSize >= 10 ? Integer.MAX_VALUE : s.stackSize))
+ .casingIndex(getCasingTextureID())
+ .dot(1)
+ .build(),
+ buildHatchAdder(GregtechMTE_ChemicalPlant.class)
+ .hatchClass(GT_MetaTileEntity_Hatch_Catalysts.class)
+ .shouldReject(t -> t.mCatalystBuses.size() >= 1)
+ .adder(GregtechMTE_ChemicalPlant::addChemicalPlantList)
+ .casingIndex(getCasingTextureID())
+ .dot(1)
+ .build(),
+ allCasingsElement))
+ .addElement('X', allCasingsElement)
+ .addElement(
+ 'M',
+ withChannel(
+ "machine",
+ addTieredBlock(
+ GregTech_API.sBlockCasings1,
+ GregtechMTE_ChemicalPlant::setMachineMeta,
+ GregtechMTE_ChemicalPlant::getMachineMeta,
+ 10)))
+ .addElement(
+ 'H',
+ withChannel(
+ "coil",
+ ofCoil(GregtechMTE_ChemicalPlant::setCoilMeta, GregtechMTE_ChemicalPlant::getCoilMeta)))
+ .addElement(
+ 'P',
+ withChannel(
+ "pipe",
+ addTieredBlock(
+ GregTech_API.sBlockCasings2,
+ GregtechMTE_ChemicalPlant::setPipeMeta,
+ GregtechMTE_ChemicalPlant::getPipeMeta,
+ 12,
+ 16)))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ private static IStructureElement<GregtechMTE_ChemicalPlant> ofSolidCasing(int aIndex) {
+ return new IStructureElement<GregtechMTE_ChemicalPlant>() {
+
+ @Override
+ public boolean check(GregtechMTE_ChemicalPlant t, World world, int x, int y, int z) {
+ if (check(aIndex, world, x, y, z)) {
+ t.checkCasing[aIndex]++;
+ t.mCasing++;
+ return true;
+ } else return false;
+ }
+
+ private boolean check(int aIndex, World world, int x, int y, int z) {
+ Block block = world.getBlock(x, y, z);
+ int meta = world.getBlockMetadata(x, y, z);
+ Block target = mTieredBlockRegistry.get(aIndex)
+ .getValue_1();
+ int targetMeta = mTieredBlockRegistry.get(aIndex)
+ .getValue_2();
+ return target.equals(block) && meta == targetMeta;
+ }
+
+ int getIndex(int size) {
+ if (size > 8) size = 8;
+ return size - 1;
+ }
+
+ @Override
+ public boolean spawnHint(GregtechMTE_ChemicalPlant t, World world, int x, int y, int z, ItemStack trigger) {
+ StructureLibAPI.hintParticle(
+ world,
+ x,
+ y,
+ z,
+ mTieredBlockRegistry.get(getIndex(trigger.stackSize))
+ .getValue_1(),
+ mTieredBlockRegistry.get(getIndex(trigger.stackSize))
+ .getValue_2());
+ return true;
+ }
+
+ @Override
+ public boolean placeBlock(GregtechMTE_ChemicalPlant t, World world, int x, int y, int z,
+ ItemStack trigger) {
+ return world.setBlock(
+ x,
+ y,
+ z,
+ mTieredBlockRegistry.get(getIndex(trigger.stackSize))
+ .getValue_1(),
+ mTieredBlockRegistry.get(getIndex(trigger.stackSize))
+ .getValue_2(),
+ 3);
+ }
+
+ @Nullable
+ @Override
+ public BlocksToPlace getBlocksToPlace(GregtechMTE_ChemicalPlant gregtechMTE_chemicalPlant, World world,
+ int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) {
+ return BlocksToPlace.create(
+ mTieredBlockRegistry.get(getIndex(trigger.stackSize))
+ .getValue_1(),
+ mTieredBlockRegistry.get(getIndex(trigger.stackSize))
+ .getValue_2());
+ }
+
+ @Override
+ public PlaceResult survivalPlaceBlock(GregtechMTE_ChemicalPlant t, World world, int x, int y, int z,
+ ItemStack trigger, AutoPlaceEnvironment env) {
+ if (check(getIndex(trigger.stackSize), world, x, y, z)) return PlaceResult.SKIP;
+ return StructureUtility.survivalPlaceBlock(
+ mTieredBlockRegistry.get(getIndex(trigger.stackSize))
+ .getValue_1(),
+ mTieredBlockRegistry.get(getIndex(trigger.stackSize))
+ .getValue_2(),
+ world,
+ x,
+ y,
+ z,
+ env.getSource(),
+ env.getActor(),
+ env.getChatter());
+ }
+ };
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(mName, stackSize, hintsOnly, 3, 6, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 3, 6, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ for (int i = 0; i < 8; i++) {
+ checkCasing[i] = 0;
+ }
+ checkPipe = 0;
+ checkMachine = 0;
+ mSolidCasingTier = 0;
+ mMachineCasingTier = 0;
+ mPipeCasingTier = 0;
+ mCoilTier = 0;
+ maxTierOfHatch = 0;
+ mCatalystBuses.clear();
+ setCoilMeta(HeatingCoilLevel.None);
+ if (checkPiece(mName, 3, 6, 0) && mCasing >= 70) {
+ for (int i = 0; i < 8; i++) {
+ if (checkCasing[i] == mCasing) {
+ mSolidCasingTier = i;
+ } else if (checkCasing[i] > 0) return false;
+ }
+ mMachineCasingTier = checkMachine - 1;
+ mPipeCasingTier = checkPipe - 12;
+ mCoilTier = checkCoil.getTier();
+ getBaseMetaTileEntity().sendBlockEvent(GregTechTileClientEvents.CHANGE_CUSTOM_DATA, getUpdateData());
+ updateHatchTexture();
+ return (mMachineCasingTier >= 9 || mMachineCasingTier >= maxTierOfHatch) && mCatalystBuses.size() <= 1;
+ }
+ return false;
+ }
+
+ public void updateHatchTexture() {
+ for (GT_MetaTileEntity_Hatch h : mCatalystBuses) h.updateTexture(getCasingTextureID());
+ for (IDualInputHatch h : mDualInputHatches) h.updateTexture(getCasingTextureID());
+ for (GT_MetaTileEntity_Hatch h : mInputBusses) h.updateTexture(getCasingTextureID());
+ for (GT_MetaTileEntity_Hatch h : mMaintenanceHatches) h.updateTexture(getCasingTextureID());
+ for (GT_MetaTileEntity_Hatch h : mEnergyHatches) h.updateTexture(getCasingTextureID());
+ for (GT_MetaTileEntity_Hatch h : mOutputBusses) h.updateTexture(getCasingTextureID());
+ for (GT_MetaTileEntity_Hatch h : mInputHatches) h.updateTexture(getCasingTextureID());
+ for (GT_MetaTileEntity_Hatch h : mOutputHatches) h.updateTexture(getCasingTextureID());
+ }
+
+ public final boolean addChemicalPlantList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) {
+ if (aTileEntity == null) {
+ return false;
+ } else {
+ IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+ if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Catalysts) {
+ return addToMachineList(aTileEntity, aBaseCasingIndex);
+ } else if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_InputBus) {
+ maxTierOfHatch = Math.max(maxTierOfHatch, ((GT_MetaTileEntity_Hatch_InputBus) aMetaTileEntity).mTier);
+ return addToMachineList(aTileEntity, aBaseCasingIndex);
+ } else if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Maintenance) {
+ return addToMachineList(aTileEntity, aBaseCasingIndex);
+ } else if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Energy) {
+ maxTierOfHatch = Math.max(maxTierOfHatch, ((GT_MetaTileEntity_Hatch_Energy) aMetaTileEntity).mTier);
+ return addToMachineList(aTileEntity, aBaseCasingIndex);
+ } else if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_OutputBus) {
+ maxTierOfHatch = Math.max(maxTierOfHatch, ((GT_MetaTileEntity_Hatch_OutputBus) aMetaTileEntity).mTier);
+ return addToMachineList(aTileEntity, aBaseCasingIndex);
+ } else if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Input) {
+ maxTierOfHatch = Math.max(maxTierOfHatch, ((GT_MetaTileEntity_Hatch_Input) aMetaTileEntity).mTier);
+ return addToMachineList(aTileEntity, aBaseCasingIndex);
+ } else if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Output) {
+ maxTierOfHatch = Math.max(maxTierOfHatch, ((GT_MetaTileEntity_Hatch_Output) aMetaTileEntity).mTier);
+ return addToMachineList(aTileEntity, aBaseCasingIndex);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected SoundResource getProcessStartSound() {
+ return SoundResource.IC2_MACHINES_ELECTROFURNACE_LOOP;
+ }
+
+ @Override
+ protected IIconContainer getActiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active;
+ }
+
+ @Override
+ protected IIconContainer getInactiveOverlay() {
+ return TexturesGtBlock.Overlay_Machine_Controller_Advanced;
+ }
+
+ @Override
+ protected int getCasingTextureId() {
+ return getCasingTextureID();
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return GTPPRecipeMaps.chemicalPlantRecipes;
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 2 * getPipeCasingTier();
+ }
+
+ private int getSolidCasingTier() {
+ return this.mSolidCasingTier;
+ }
+
+ private int getMachineCasingTier() {
+ return mMachineCasingTier;
+ }
+
+ private int getPipeCasingTier() {
+ return mPipeCasingTier;
+ }
+
+ private int getCasingTextureID() {
+ // Check the Tier Client Side
+ int aTier = mSolidCasingTier;
+ return getCasingTextureIdForTier(aTier);
+ }
+
+ public boolean addToMachineList(IGregTechTileEntity aTileEntity) {
+ int aMaxTier = getMachineCasingTier();
+ final IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+ if (aMetaTileEntity instanceof GT_MetaTileEntity_TieredMachineBlock aMachineBlock) {
+ int aTileTier = aMachineBlock.mTier;
+ if (aTileTier > aMaxTier) {
+ log("Hatch tier too high.");
+ return false;
+ } else {
+ return addToMachineList(aTileEntity, getCasingTextureID());
+ }
+ } else {
+ log("Bad Tile Entity being added to hatch map."); // Shouldn't ever happen, but.. ya know..
+ return false;
+ }
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ super.saveNBTData(aNBT);
+ aNBT.setInteger("mSolidCasingTier", this.mSolidCasingTier);
+ aNBT.setInteger("mMachineCasingTier", this.mMachineCasingTier);
+ aNBT.setInteger("mPipeCasingTier", this.mPipeCasingTier);
+ aNBT.setInteger("mCoilTier", this.mCoilTier);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ mSolidCasingTier = aNBT.getInteger("mSolidCasingTier");
+ mMachineCasingTier = aNBT.getInteger("mMachineCasingTier");
+ mPipeCasingTier = aNBT.getInteger("mPipeCasingTier");
+ mCoilTier = aNBT.getInteger("mCoilTier");
+ }
+
+ @Override
+ public boolean addToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) {
+ final IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+ if (aMetaTileEntity == null) {
+ return false;
+ }
+ if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Catalysts) {
+ log("Found GT_MetaTileEntity_Hatch_Catalysts");
+ return addToMachineListInternal(mCatalystBuses, aMetaTileEntity, aBaseCasingIndex);
+ }
+ return super.addToMachineList(aTileEntity, aBaseCasingIndex);
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerTick(final ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ public int getMaxCatalystDurability() {
+ return 50;
+ }
+
+ @Override
+ public byte getUpdateData() {
+ return (byte) mSolidCasingTier;
+ }
+
+ @Override
+ public void receiveClientEvent(byte aEventID, byte aValue) {
+ super.receiveClientEvent(aEventID, aValue);
+ if (aEventID == GregTechTileClientEvents.CHANGE_CUSTOM_DATA && (aValue & 0x80) == 0) {
+ // received an update data from above method
+ // if no &0x80 clause it might catch the noop texture page event
+ mSolidCasingTier = aValue;
+ }
+ }
+
+ private void damageCatalyst(@Nonnull ItemStack aStack, int minParallel) {
+ // Awakened Draconium Coils with Tungstensteel Pipe Casings (or above) no longer consume catalysts.
+ if (!isCatalystDamageable()) return;
+ for (int i = 0; i < minParallel; i++) {
+ if (MathUtils.randFloat(0, 10000000) / 10000000f < (1.2f - (0.2 * this.mPipeCasingTier))) {
+ int damage = getDamage(aStack) + 1;
+ if (damage >= getMaxCatalystDurability()) {
+ addOutput(CI.getEmptyCatalyst(1));
+ aStack.stackSize -= 1;
+ return;
+ } else {
+ setDamage(aStack, damage);
+ }
+ }
+ }
+ }
+
+ private boolean isCatalystDamageable() {
+ return this.mCoilTier < 10 || this.mPipeCasingTier < 4;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic() {
+
+ ItemStack catalyst;
+
+ @NotNull
+ @Override
+ protected CheckRecipeResult validateRecipe(@NotNull GT_Recipe recipe) {
+ if (recipe.mSpecialValue > mSolidCasingTier) {
+ return CheckRecipeResultRegistry.insufficientMachineTier(recipe.mSpecialValue + 1);
+ }
+ // checks if it has a catalyst
+ ItemStack catalystInRecipe = null;
+ for (ItemStack item : recipe.mInputs) {
+ if (ItemUtils.isCatalyst(item)) {
+ catalystInRecipe = item;
+ break;
+ }
+ }
+
+ if (catalystInRecipe != null) {
+ catalyst = findCatalyst(getCatalystInputs().toArray(new ItemStack[0]), catalystInRecipe);
+ if (catalyst == null) {
+ return SimpleCheckRecipeResult.ofFailure("no_catalyst");
+ }
+ }
+ return CheckRecipeResultRegistry.SUCCESSFUL;
+ }
+
+ @NotNull
+ @Override
+ public CheckRecipeResult process() {
+ ArrayList<ItemStack> inputItemsList = new ArrayList<>(Arrays.asList(inputItems));
+ inputItemsList.addAll(getCatalystInputs());
+ inputItems = inputItemsList.toArray(new ItemStack[0]);
+ return super.process();
+ }
+
+ @NotNull
+ @Override
+ protected CheckRecipeResult onRecipeStart(@NotNull GT_Recipe recipe) {
+ if (catalyst != null) {
+ damageCatalyst(catalyst, getCurrentParallels());
+ }
+ return super.onRecipeStart(recipe);
+ }
+ }.setMaxParallelSupplier(this::getMaxParallelRecipes);
+ }
+
+ @Override
+ protected void setupProcessingLogic(ProcessingLogic logic) {
+ super.setupProcessingLogic(logic);
+ // Same speed bonus as pyro oven
+ logic.setSpeedBonus(2F / (1 + this.mCoilTier));
+ }
+
+ @Override
+ public void updateSlots() {
+ super.updateSlots();
+ for (GT_MetaTileEntity_Hatch_Catalysts h : mCatalystBuses) {
+ h.updateSlots();
+ h.tryFillUsageSlots();
+ }
+ }
+
+ private ItemStack findCatalyst(ItemStack[] aItemInputs, ItemStack catalyst) {
+ if (aItemInputs != null) {
+ for (ItemStack item : aItemInputs) {
+ if (GT_Utility.areStacksEqual(item, catalyst, true)) {
+ return item;
+ }
+ }
+ }
+ return null;
+ }
+
+ private int getDamage(@Nonnull ItemStack aStack) {
+ return ItemGenericChemBase.getCatalystDamage(aStack);
+ }
+
+ private void setDamage(@Nonnull ItemStack aStack, int aAmount) {
+ ItemGenericChemBase.setCatalystDamage(aStack, aAmount);
+ }
+
+ /*
+ * Catalyst Handling
+ */
+ public ArrayList<ItemStack> getCatalystInputs() {
+ ArrayList<ItemStack> tItems = new ArrayList<>();
+ for (GT_MetaTileEntity_Hatch_Catalysts tHatch : filterValidMTEs(mCatalystBuses)) {
+ AutoMap<ItemStack> aHatchContent = tHatch.getContentUsageSlots();
+ if (!aHatchContent.isEmpty()) {
+ tItems.addAll(aHatchContent);
+ }
+ }
+ return tItems;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/mega/GregTechMetaTileEntity_MegaAlloyBlastSmelter.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/mega/GregTechMetaTileEntity_MegaAlloyBlastSmelter.java
new file mode 100644
index 0000000000..1679629c88
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/mega/GregTechMetaTileEntity_MegaAlloyBlastSmelter.java
@@ -0,0 +1,468 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production.mega;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.withChannel;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.ExoticEnergy;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputBus;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+import static gregtech.api.util.GT_StructureUtility.ofCoil;
+import static gregtech.api.util.GT_Utility.filterValidMTEs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.StatCollector;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.github.bartimaeusnek.bartworks.API.BorosilicateGlass;
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.GT_Values;
+import gregtech.api.enums.HeatingCoilLevel;
+import gregtech.api.enums.TAE;
+import gregtech.api.enums.Textures;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_ExtendedPowerMultiBlockBase;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.render.TextureFactory;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_OverclockCalculator;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.api.recipe.GTPPRecipeMaps;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GregTechMetaTileEntity_MegaAlloyBlastSmelter
+ extends GT_MetaTileEntity_ExtendedPowerMultiBlockBase<GregTechMetaTileEntity_MegaAlloyBlastSmelter>
+ implements ISurvivalConstructable {
+
+ private static final int MAX_PARALLELS = 256;
+ private HeatingCoilLevel coilLevel;
+ private byte glassTier = -1;
+ private boolean hasNormalCoils;
+
+ private static final IStructureDefinition<GregTechMetaTileEntity_MegaAlloyBlastSmelter> STRUCTURE_DEFINITION = StructureDefinition
+ .<GregTechMetaTileEntity_MegaAlloyBlastSmelter>builder()
+ .addShape(
+ "main",
+ new String[][] {
+ { " ", " ", " ", " ", " ", " ",
+ " ", " ", " ", " ", " ", " ",
+ " ", " DDDDD ", " CCCCC ", " AEEEA ", " AE~EA ", " AEEEA ",
+ " CCCCC ", " ZZZZZ " },
+ { " DDDDD ", " AAAAA ", " AAAAA ", " AAAAA ", " AAAAA ", " AAAAA ",
+ " AAAAA ", " AAAAA ", " AAAAA ", " AAAAA ", " AAAAA ", " AAAAA ",
+ " DDDDD ", " D D ", " C C ", " A A ", " A A ", " A A ",
+ " C C ", " ZZZZZZZ " },
+ { " DDDDDDD ", " ABBBBBA ", " ABBBBBA ", " ABBBBBA ", " ABBBBBA ", " ABBBBBA ",
+ " ABBBBBA ", " ABBBBBA ", " ABBBBBA ", " ABBBBBA ", " ABBBBBA ", " ABBBBBA ",
+ " DBBBBBD ", " D BBBBB D ", " C BBBBB C ", " A BBBBB A ", " A BBBBB A ", " A BBBBB A ",
+ " C BBBBB C ", " ZZZZZZZZZ " },
+ { " DDDDDDDDD ", " AB BA ", " AB BA ", " AB BA ", " AB BA ", " AB BA ",
+ " AB BA ", " AB BA ", " AB BA ", " AB BA ", " AB BA ", " AB BA ",
+ " DB BD ", "D B B D", "C B B C", "A B B A", "A B B A", "A B B A",
+ "C B B C", "ZZZZZZZZZZZ" },
+ { " DDDDDDDDD ", " AB BA ", " AB BA ", " AB BA ", " AB BA ", " AB BA ",
+ " AB BA ", " AB BA ", " AB BA ", " AB BA ", " AB BA ", " AB BA ",
+ " DB BD ", "D B B D", "C B B C", "A B B A", "A B B A", "A B B A",
+ "C B B C", "ZZZZZZZZZZZ" },
+ { " DDDDFDDDD ", " AB BA ", " AB BA ", " AB BA ", " AB BA ", " AB BA ",
+ " AB BA ", " AB BA ", " AB BA ", " AB BA ", " AB BA ", " AB BA ",
+ " DB BD ", "D B B D", "C B B C", "A B B A", "A B B A", "A B B A",
+ "C B B C", "ZZZZZZZZZZZ" },
+ { " DDDDDDDDD ", " AB BA ", " AB BA ", " AB BA ", " AB BA ", " AB BA ",
+ " AB BA ", " AB BA ", " AB BA ", " AB BA ", " AB BA ", " AB BA ",
+ " DB BD ", "D B B D", "C B B C", "A B B A", "A B B A", "A B B A",
+ "C B B C", "ZZZZZZZZZZZ" },
+ { " DDDDDDDDD ", " AB BA ", " AB BA ", " AB BA ", " AB BA ", " AB BA ",
+ " AB BA ", " AB BA ", " AB BA ", " AB BA ", " AB BA ", " AB BA ",
+ " DB BD ", "D B B D", "C B B C", "A B B A", "A B B A", "A B B A",
+ "C B B C", "ZZZZZZZZZZZ" },
+ { " DDDDDDD ", " ABBBBBA ", " ABBBBBA ", " ABBBBBA ", " ABBBBBA ", " ABBBBBA ",
+ " ABBBBBA ", " ABBBBBA ", " ABBBBBA ", " ABBBBBA ", " ABBBBBA ", " ABBBBBA ",
+ " DBBBBBD ", " D BBBBB D ", " C BBBBB C ", " A BBBBB A ", " A BBBBB A ", " A BBBBB A ",
+ " C BBBBB C ", " ZZZZZZZZZ " },
+ { " DDDDD ", " AAAAA ", " AAAAA ", " AAAAA ", " AAAAA ", " AAAAA ",
+ " AAAAA ", " AAAAA ", " AAAAA ", " AAAAA ", " AAAAA ", " AAAAA ",
+ " DDDDD ", " D D ", " C C ", " A A ", " A A ", " A A ",
+ " C C ", " ZZZZZZZ " },
+ { " ", " ", " ", " ", " ", " ",
+ " ", " ", " ", " ", " ", " ",
+ " ", " DDDDD ", " CCCCC ", " AAAAA ", " AAAAA ", " AAAAA ",
+ " CCCCC ", " ZZZZZ " } })
+ .addElement(
+ 'B',
+ withChannel(
+ "coil",
+ ofChain(
+ onElementPass(
+ te -> te.hasNormalCoils = false,
+ ofCoil(
+ GregTechMetaTileEntity_MegaAlloyBlastSmelter::setCoilLevel,
+ GregTechMetaTileEntity_MegaAlloyBlastSmelter::getCoilLevel)),
+ onElementPass(te -> te.hasNormalCoils = true, ofBlock(ModBlocks.blockCasingsMisc, 14)))))
+
+ .addElement(
+ 'Z',
+ buildHatchAdder(GregTechMetaTileEntity_MegaAlloyBlastSmelter.class)
+ .atLeast(InputHatch, OutputHatch, InputBus, OutputBus, Energy, ExoticEnergy)
+ .casingIndex(TAE.GTPP_INDEX(15))
+ .dot(1)
+ .buildAndChain(ofBlock(ModBlocks.blockCasingsMisc, 15)))
+ .addElement(
+ 'E',
+ buildHatchAdder(GregTechMetaTileEntity_MegaAlloyBlastSmelter.class).atLeast(Maintenance)
+ .casingIndex(TAE.GTPP_INDEX(15))
+ .dot(2)
+ .buildAndChain(ofBlock(ModBlocks.blockCasingsMisc, 15)))
+ .addElement('D', ofBlock(ModBlocks.blockCasingsMisc, 15))
+ .addElement('C', ofBlock(ModBlocks.blockCasingsMisc, 14))
+ .addElement(
+ 'A',
+ withChannel(
+ "glass",
+ BorosilicateGlass.ofBoroGlass((byte) -1, (te, t) -> te.glassTier = t, te -> te.glassTier)))
+ .addElement('F', Muffler.newAny(TAE.GTPP_INDEX(15), 3))
+ .build();
+
+ public GregTechMetaTileEntity_MegaAlloyBlastSmelter(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregTechMetaTileEntity_MegaAlloyBlastSmelter(String aName) {
+ super(aName);
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic() {
+
+ @NotNull
+ @Override
+ protected CheckRecipeResult validateRecipe(@NotNull GT_Recipe recipe) {
+ if (glassTier < GT_Utility.getTier(recipe.mEUt)) {
+ return CheckRecipeResultRegistry.insufficientMachineTier(GT_Utility.getTier(recipe.mEUt));
+ }
+ return CheckRecipeResultRegistry.SUCCESSFUL;
+ }
+
+ @NotNull
+ @Override
+ protected GT_OverclockCalculator createOverclockCalculator(@NotNull GT_Recipe recipe) {
+ return super.createOverclockCalculator(recipe)
+ .setSpeedBoost((float) (1.0 - getCoilDiscount(coilLevel)));
+ }
+ }.setMaxParallel(MAX_PARALLELS);
+ }
+
+ @Override
+ protected void setProcessingLogicPower(ProcessingLogic logic) {
+ logic.setAvailableVoltage(getMaxInputEu());
+ logic.setAvailableAmperage(1);
+ }
+
+ @Override
+ public boolean addOutputToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) {
+ boolean exotic = addExoticEnergyInputToMachineList(aTileEntity, aBaseCasingIndex);
+ return super.addToMachineList(aTileEntity, aBaseCasingIndex) || exotic;
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ glassTier = -1;
+ coilLevel = HeatingCoilLevel.None;
+ if (!checkPiece("main", 5, 16, 0)) return false;
+ if (hasNormalCoils) coilLevel = HeatingCoilLevel.None;
+ if (mMaintenanceHatches.size() != 1) return false;
+ if (mMufflerHatches.size() != 1) return false;
+ if (this.glassTier < 10 && !getExoticAndNormalEnergyHatchList().isEmpty()) {
+ for (GT_MetaTileEntity_Hatch hatchEnergy : getExoticAndNormalEnergyHatchList()) {
+ if (this.glassTier < hatchEnergy.mTier) {
+ return false;
+ }
+ }
+ }
+ // Disallow lasers if the glass is below UV tier
+ if (glassTier < 8) {
+ for (GT_MetaTileEntity_Hatch hatchEnergy : getExoticEnergyHatches()) {
+ if (hatchEnergy.getConnectionType() == GT_MetaTileEntity_Hatch.ConnectionType.LASER) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(ItemStack aStack) {
+ return false;
+ }
+
+ public double getCoilDiscount(HeatingCoilLevel lvl) {
+ // Since there are only 14 tiers (starting from 0), this is what the function is.
+ double unRounded = (lvl != null ? lvl.getTier() : 0) / 130.0D;
+ if (unRounded < 0) return 1F;
+ double rounded = Math.floor(unRounded * 1000) / 1000;
+
+ return Math.max(0, rounded);
+ }
+
+ @Override
+ public void explodeMultiblock() {
+ super.explodeMultiblock();
+ }
+
+ @Override
+ public List<GT_MetaTileEntity_Hatch> getExoticAndNormalEnergyHatchList() {
+ List<GT_MetaTileEntity_Hatch> tHatches = new ArrayList<>();
+ tHatches.addAll(mExoticEnergyHatches);
+ tHatches.addAll(mEnergyHatches);
+ return tHatches;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece("main", stackSize, hintsOnly, 5, 16, 0);
+ }
+
+ @Override
+ public IStructureDefinition<GregTechMetaTileEntity_MegaAlloyBlastSmelter> getStructureDefinition() {
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType("Fluid Alloy Cooker")
+ .addInfo("Controller block for the Mega Alloy Blast Smelter")
+ .addInfo(
+ "Runs the same recipes as the normal ABS, except with up to " + EnumChatFormatting.BOLD
+ + EnumChatFormatting.UNDERLINE
+ + MAX_PARALLELS
+ + EnumChatFormatting.RESET
+ + EnumChatFormatting.GRAY
+ + " parallels.")
+ .addInfo("Every coil tier above cupronickel grants a speed bonus, based on this function:")
+ .addInfo("Bonus = TIER / 150, rounded to the nearest thousandth.")
+ .addInfo(
+ EnumChatFormatting.ITALIC
+ + "Can also use normal ABS coils in their place instead, if you don't like the bonuses :)"
+ + EnumChatFormatting.RESET
+ + EnumChatFormatting.GRAY)
+ .addInfo("The glass limits the tier of the energy hatch. UEV glass unlocks all tiers.")
+ .addInfo("UV glass required for TecTech laser hatches.")
+ .addInfo(
+ EnumChatFormatting.ITALIC + "\"all it does is make metals hot\""
+ + EnumChatFormatting.RESET
+ + EnumChatFormatting.GRAY)
+ .beginStructureBlock(11, 20, 11, false)
+ .addStructureInfo("This structure is too complex! See schematic for details.")
+ .addMaintenanceHatch("Around the controller", 2)
+ .addOtherStructurePart("Input Bus, Output Bus, Input Hatch, Output Bus, Energy Hatch", "Bottom Casing", 1)
+ .addMufflerHatch("1 in the center of the top layer", 3)
+ .toolTipFinisher(
+ EnumChatFormatting.AQUA + "MadMan310 "
+ + EnumChatFormatting.GRAY
+ + "via "
+ + EnumChatFormatting.RED
+ + "GT++");
+ return tt;
+ }
+
+ @Override
+ public String[] getInfoData() {
+ long storedEnergy = 0;
+ long maxEnergy = 0;
+ int paras = getBaseMetaTileEntity().isActive() ? processingLogic.getCurrentParallels() : 0;
+ int discountP = (int) (getCoilDiscount(coilLevel) * 1000) / 10;
+
+ for (GT_MetaTileEntity_Hatch tHatch : filterValidMTEs(mExoticEnergyHatches)) {
+ storedEnergy += tHatch.getBaseMetaTileEntity()
+ .getStoredEU();
+ maxEnergy += tHatch.getBaseMetaTileEntity()
+ .getEUCapacity();
+ }
+
+ return new String[] { "------------ Critical Information ------------",
+ StatCollector.translateToLocal("GT5U.multiblock.Progress") + ": "
+ + EnumChatFormatting.GREEN
+ + GT_Utility.formatNumbers(mProgresstime)
+ + EnumChatFormatting.RESET
+ + "t / "
+ + EnumChatFormatting.YELLOW
+ + GT_Utility.formatNumbers(mMaxProgresstime)
+ + EnumChatFormatting.RESET
+ + "t",
+ StatCollector.translateToLocal("GT5U.multiblock.energy") + ": "
+ + EnumChatFormatting.GREEN
+ + GT_Utility.formatNumbers(storedEnergy)
+ + EnumChatFormatting.RESET
+ + " EU / "
+ + EnumChatFormatting.YELLOW
+ + GT_Utility.formatNumbers(maxEnergy)
+ + EnumChatFormatting.RESET
+ + " EU",
+ StatCollector.translateToLocal("GT5U.multiblock.usage") + ": "
+ + EnumChatFormatting.RED
+ + GT_Utility.formatNumbers(-lEUt)
+ + EnumChatFormatting.RESET
+ + " EU/t",
+ StatCollector.translateToLocal("GT5U.multiblock.mei") + ": "
+ + EnumChatFormatting.YELLOW
+ + GT_Utility.formatNumbers(getAverageInputVoltage())
+ + EnumChatFormatting.RESET
+ + " EU/t(*"
+ + EnumChatFormatting.YELLOW
+ + GT_Utility.formatNumbers(getMaxInputAmps())
+ + EnumChatFormatting.RESET
+ + "A) "
+ + StatCollector.translateToLocal("GT5U.machines.tier")
+ + ": "
+ + EnumChatFormatting.YELLOW
+ + GT_Values.VN[GT_Utility.getTier(getAverageInputVoltage())]
+ + EnumChatFormatting.RESET,
+ "Parallels: " + EnumChatFormatting.BLUE + paras + EnumChatFormatting.RESET,
+ "Coil Discount: " + EnumChatFormatting.BLUE + discountP + "%" + EnumChatFormatting.RESET,
+ "-----------------------------------------" };
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GregTechMetaTileEntity_MegaAlloyBlastSmelter(this.mName);
+ }
+
+ @Override
+ public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection facing,
+ int aColorIndex, boolean aActive, boolean aRedstone) {
+ if (side == facing) {
+ if (aActive) {
+ return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(TAE.GTPP_INDEX(15)),
+ TextureFactory.builder()
+ .addIcon(TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active)
+ .extFacing()
+ .build() };
+ }
+ return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(TAE.GTPP_INDEX(15)),
+ TextureFactory.builder()
+ .addIcon(TexturesGtBlock.Overlay_Machine_Controller_Advanced)
+ .extFacing()
+ .build() };
+ }
+ return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(TAE.GTPP_INDEX(15)) };
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return GTPPRecipeMaps.alloyBlastSmelterRecipes;
+ }
+
+ public HeatingCoilLevel getCoilLevel() {
+ return coilLevel;
+ }
+
+ public void setCoilLevel(HeatingCoilLevel coilLevel) {
+ this.coilLevel = coilLevel;
+ }
+
+ @Override
+ public final void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+ if (aPlayer.isSneaking()) {
+ // Lock to single recipe
+ super.onScrewdriverRightClick(side, aPlayer, aX, aY, aZ);
+ } else {
+ inputSeparation = !inputSeparation;
+ GT_Utility.sendChatToPlayer(
+ aPlayer,
+ StatCollector.translateToLocal("GT5U.machines.separatebus") + " " + inputSeparation);
+ }
+ }
+
+ @Override
+ public boolean onWireCutterRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer aPlayer,
+ float aX, float aY, float aZ, ItemStack aTool) {
+ if (aPlayer.isSneaking()) {
+ batchMode = !batchMode;
+ if (batchMode) {
+ GT_Utility.sendChatToPlayer(aPlayer, "Batch recipes.");
+ } else {
+ GT_Utility.sendChatToPlayer(aPlayer, "Don't batch recipes.");
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public int getPollutionPerSecond(ItemStack aStack) {
+ return 102400;
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ return survivialBuildPiece("main", stackSize, 5, 16, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ this.glassTier = aNBT.getByte("glassTier");
+ if (!aNBT.hasKey(INPUT_SEPARATION_NBT_KEY)) {
+ inputSeparation = aNBT.getBoolean("separateBusses");
+ }
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ aNBT.setByte("glassTier", glassTier);
+ super.saveNBTData(aNBT);
+ }
+
+ @Override
+ public boolean supportsInputSeparation() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsBatchMode() {
+ return true;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GT_MTE_LargeTurbine_Gas.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GT_MTE_LargeTurbine_Gas.java
new file mode 100644
index 0000000000..84fac40265
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GT_MTE_LargeTurbine_Gas.java
@@ -0,0 +1,208 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production.turbines;
+
+import static gtPlusPlus.core.lib.CORE.RANDOM;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.fluids.Fluid;
+import net.minecraftforge.fluids.FluidStack;
+
+import org.jetbrains.annotations.NotNull;
+
+import gregtech.api.enums.Materials;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.objects.GT_RenderedTexture;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.SimpleCheckRecipeResult;
+import gregtech.api.recipe.maps.FuelBackend;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+@SuppressWarnings("deprecation")
+public class GT_MTE_LargeTurbine_Gas extends GregtechMetaTileEntity_LargerTurbineBase {
+
+ private static final HashSet<Fluid> BLACKLIST = new HashSet<>();
+
+ static {
+ BLACKLIST.add(
+ Materials.Benzene.getFluid(0)
+ .getFluid());
+ }
+
+ public GT_MTE_LargeTurbine_Gas(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GT_MTE_LargeTurbine_Gas(String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GT_MTE_LargeTurbine_Gas(mName);
+ }
+
+ @Override
+ public int getCasingMeta() {
+ return 3;
+ }
+
+ @Override
+ public int getCasingTextureIndex() {
+ return 58;
+ }
+
+ @Override
+ protected boolean requiresOutputHatch() {
+ return false;
+ }
+
+ @Override
+ public int getPollutionPerSecond(ItemStack aStack) {
+ return 4000;
+ }
+
+ @Override
+ public int getFuelValue(FluidStack aLiquid) {
+ if (aLiquid == null) {
+ return 0;
+ }
+ GT_Recipe tFuel = getRecipeMap().getBackend()
+ .findFuel(aLiquid);
+ if (tFuel != null) {
+ return tFuel.mSpecialValue;
+ }
+ return 0;
+ }
+
+ @Override
+ public RecipeMap<FuelBackend> getRecipeMap() {
+ return RecipeMaps.gasTurbineFuels;
+ }
+
+ @Override
+ public int getRecipeCatalystPriority() {
+ return -20;
+ }
+
+ @Override
+ protected boolean filtersFluid() {
+ return false;
+ }
+
+ @Override
+ public @NotNull CheckRecipeResult checkProcessing() {
+ List<FluidStack> fluids = getStoredFluids();
+ for (FluidStack fluid : fluids) {
+ if (fluid != null && BLACKLIST.contains(fluid.getFluid())) {
+ return SimpleCheckRecipeResult.ofFailure("fuel_blacklisted");
+ }
+ }
+ return super.checkProcessing();
+ }
+
+ @Override
+ long fluidIntoPower(ArrayList<FluidStack> aFluids, long aOptFlow, int aBaseEff, float[] flowMultipliers) {
+ if (aFluids.size() >= 1) {
+ int tEU = 0;
+ int actualOptimalFlow = 0;
+ FluidStack firstFuelType = new FluidStack(aFluids.get(0), 0); // Identify a SINGLE type of fluid to process.
+ // Doesn't matter which one. Ignore the rest!
+ int fuelValue = getFuelValue(firstFuelType);
+ // log("Fuel Value of "+aFluids.get(0).getLocalizedName()+" is "+fuelValue+"eu");
+ if (aOptFlow < fuelValue) {
+ // turbine too weak and/or fuel too powerful
+ // at least consume 1L
+ this.realOptFlow = 1;
+ // wastes the extra fuel and generate aOptFlow directly
+ depleteInput(new FluidStack(firstFuelType, 1));
+ this.storedFluid += 1;
+ return GT_Utility.safeInt((long) aOptFlow * (long) aBaseEff / 10000L);
+ }
+
+ actualOptimalFlow = GT_Utility.safeInt((long) (aOptFlow * (double) flowMultipliers[1] / fuelValue));
+ this.realOptFlow = actualOptimalFlow;
+
+ int remainingFlow = GT_Utility.safeInt((long) (actualOptimalFlow * 1.25f)); // Allowed to use up to 125% of
+ // optimal flow. Variable
+ // required outside of loop for
+ // multi-hatch scenarios.
+ int flow = 0;
+ int totalFlow = 0;
+
+ storedFluid = 0;
+ for (FluidStack aFluid : aFluids) {
+ if (aFluid.isFluidEqual(firstFuelType)) {
+ flow = Math.min(aFluid.amount, remainingFlow); // try to use up to 125% of optimal flow w/o
+ // exceeding remainingFlow
+ depleteInput(new FluidStack(aFluid, flow)); // deplete that amount
+ this.storedFluid += aFluid.amount;
+ remainingFlow -= flow; // track amount we're allowed to continue depleting from hatches
+ totalFlow += flow; // track total input used
+ }
+ }
+ if (totalFlow <= 0) return 0;
+ tEU = GT_Utility.safeInt((long) totalFlow * fuelValue);
+
+ if (totalFlow == actualOptimalFlow) {
+ tEU = GT_Utility.safeInt((long) tEU * (long) aBaseEff / 10000L);
+ } else {
+ float efficiency = 1.0f - Math.abs((totalFlow - actualOptimalFlow) / (float) actualOptimalFlow);
+ tEU *= efficiency;
+ tEU = GT_Utility.safeInt((long) tEU * (long) aBaseEff / 10000L);
+ }
+
+ return tEU;
+ }
+ return 0;
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return (RANDOM.nextInt(4) == 0) ? 0 : 1;
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ super.saveNBTData(aNBT);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Large Gas Turbine";
+ }
+
+ @Override
+ protected String getTurbineType() {
+ return "Gas";
+ }
+
+ @Override
+ protected String getCasingName() {
+ return "Reinforced Gas Turbine Casing";
+ }
+
+ @Override
+ protected ITexture getTextureFrontFace() {
+ return new GT_RenderedTexture(TexturesGtBlock.Overlay_Machine_Controller_Advanced);
+ }
+
+ @Override
+ protected ITexture getTextureFrontFaceActive() {
+ return new GT_RenderedTexture(TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active);
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GT_MTE_LargeTurbine_Plasma.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GT_MTE_LargeTurbine_Plasma.java
new file mode 100644
index 0000000000..db99b52be1
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GT_MTE_LargeTurbine_Plasma.java
@@ -0,0 +1,314 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production.turbines;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.fluids.Fluid;
+import net.minecraftforge.fluids.FluidRegistry;
+import net.minecraftforge.fluids.FluidStack;
+
+import org.jetbrains.annotations.NotNull;
+
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.items.GT_MetaGenerated_Tool;
+import gregtech.api.objects.GT_RenderedTexture;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.recipe.check.SimpleCheckRecipeResult;
+import gregtech.api.recipe.maps.FuelBackend;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.GT_Utility;
+import gregtech.api.util.shutdown.ShutDownReasonRegistry;
+import gtPlusPlus.core.util.math.MathUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Turbine;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+@SuppressWarnings("deprecation")
+public class GT_MTE_LargeTurbine_Plasma extends GregtechMetaTileEntity_LargerTurbineBase {
+
+ private static final HashSet<Fluid> BLACKLIST = new HashSet<>();
+
+ public GT_MTE_LargeTurbine_Plasma(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GT_MTE_LargeTurbine_Plasma(String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GT_MTE_LargeTurbine_Plasma(mName);
+ }
+
+ @Override
+ public int getCasingMeta() {
+ return 4;
+ }
+
+ @Override
+ public int getCasingTextureIndex() {
+ return 60;
+ }
+
+ @Override
+ protected boolean requiresOutputHatch() {
+ return true;
+ }
+
+ @Override
+ public int getPollutionPerSecond(ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public int getFuelValue(FluidStack aLiquid) {
+ if (aLiquid == null) {
+ return 0;
+ }
+ GT_Recipe tFuel = getRecipeMap().getBackend()
+ .findFuel(aLiquid);
+ if (tFuel != null) {
+ return tFuel.mSpecialValue;
+ }
+ return 0;
+ }
+
+ @Override
+ public RecipeMap<FuelBackend> getRecipeMap() {
+ return RecipeMaps.plasmaFuels;
+ }
+
+ @Override
+ public int getRecipeCatalystPriority() {
+ return -20;
+ }
+
+ @Override
+ protected boolean filtersFluid() {
+ return false;
+ }
+
+ @Override
+ public @NotNull CheckRecipeResult checkProcessing() {
+
+ try {
+ ArrayList<GT_MetaTileEntity_Hatch_Turbine> aEmptyTurbineRotorHatches = getEmptyTurbineAssemblies();
+ if (aEmptyTurbineRotorHatches.size() > 0) {
+ hatch: for (GT_MetaTileEntity_Hatch_Turbine aHatch : aEmptyTurbineRotorHatches) {
+ ArrayList<ItemStack> aTurbines = getAllBufferedTurbines();
+ for (ItemStack aTurbineItem : aTurbines) {
+ if (aTurbineItem == null) {
+ continue;
+ }
+ if (aHatch.insertTurbine(aTurbineItem.copy())) {
+ depleteTurbineFromStock(aTurbineItem);
+ continue hatch;
+ }
+ }
+ }
+ }
+
+ if (getEmptyTurbineAssemblies().size() > 0 || !areAllTurbinesTheSame()) {
+ stopMachine(ShutDownReasonRegistry.NO_TURBINE);
+ return CheckRecipeResultRegistry.NO_TURBINE_FOUND;
+ }
+
+ ArrayList<FluidStack> tFluids = getStoredFluids();
+
+ if (tFluids.size() > 0) {
+ for (FluidStack fluid : tFluids) {
+ if (fluid != null && BLACKLIST.contains(fluid.getFluid())) {
+ return SimpleCheckRecipeResult.ofFailure("fuel_blacklisted");
+ }
+ }
+ if (baseEff == 0 || optFlow == 0
+ || counter >= 512
+ || this.getBaseMetaTileEntity()
+ .hasWorkJustBeenEnabled()
+ || this.getBaseMetaTileEntity()
+ .hasInventoryBeenModified()) {
+ counter = 0;
+
+ float aTotalBaseEff = 0;
+ float aTotalOptimalFlow = 0;
+
+ ItemStack aStack = getFullTurbineAssemblies().get(0)
+ .getTurbine();
+ aTotalBaseEff += GT_Utility.safeInt(
+ (long) ((5F + ((GT_MetaGenerated_Tool) aStack.getItem()).getToolCombatDamage(aStack)) * 1000F));
+ aTotalOptimalFlow += GT_Utility.safeInt(
+ (long) Math.max(
+ Float.MIN_NORMAL,
+ ((GT_MetaGenerated_Tool) aStack.getItem()).getToolStats(aStack)
+ .getSpeedMultiplier() * GT_MetaGenerated_Tool.getPrimaryMaterial(aStack).mToolSpeed
+ * 50));
+
+ // Calculate total EU/t (as shown on turbine tooltip (Fast mode doesn't affect))
+ double aEUPerTurbine = aTotalOptimalFlow * 40
+ * 0.0105
+ * GT_MetaGenerated_Tool.getPrimaryMaterial(aStack).mPlasmaMultiplier
+ * (50.0f + (10.0f * ((GT_MetaGenerated_Tool) aStack.getItem()).getToolCombatDamage(aStack)));
+ aTotalOptimalFlow *= getSpeedMultiplier();
+
+ if (aTotalOptimalFlow < 0) {
+ aTotalOptimalFlow = 100;
+ }
+
+ flowMultipliers[0] = GT_MetaGenerated_Tool.getPrimaryMaterial(aStack).mSteamMultiplier;
+ flowMultipliers[1] = GT_MetaGenerated_Tool.getPrimaryMaterial(aStack).mGasMultiplier;
+ flowMultipliers[2] = GT_MetaGenerated_Tool.getPrimaryMaterial(aStack).mPlasmaMultiplier;
+ baseEff = MathUtils.roundToClosestInt(aTotalBaseEff);
+ optFlow = MathUtils.roundToClosestInt(aTotalOptimalFlow);
+ euPerTurbine = MathUtils.roundToClosestInt(aEUPerTurbine);
+ if (optFlow <= 0 || baseEff <= 0) {
+ stopMachine(ShutDownReasonRegistry.NONE); // in case the turbine got removed
+ return CheckRecipeResultRegistry.NO_FUEL_FOUND;
+ }
+ } else {
+ counter++;
+ }
+ }
+
+ // How much the turbine should be producing with this flow
+ long newPower = fluidIntoPower(tFluids, optFlow, baseEff, flowMultipliers);
+
+ // Reduce produced power depending on the ratio between fuel value and turbine EU/t with the following
+ // formula:
+ // EU/t = EU/t * MIN(1, ( ( (FuelValue / 200) ^ 2 ) / EUPerTurbine))
+ int fuelValue = 0;
+ if (tFluids.size() > 0) {
+ fuelValue = getFuelValue(new FluidStack(tFluids.get(0), 0));
+ }
+ float magicValue = (fuelValue * 0.005f) * (fuelValue * 0.005f);
+ float efficiencyLoss = Math.min(1.0f, magicValue / euPerTurbine);
+ newPower *= efficiencyLoss;
+
+ long difference = newPower - this.lEUt; // difference between current output and new output
+
+ // Magic numbers: can always change by at least 10 eu/t, but otherwise by at most 1 percent of the
+ // difference in power level (per tick)
+ // This is how much the turbine can actually change during this tick
+ int maxChangeAllowed = Math.max(10, GT_Utility.safeInt((long) Math.abs(difference) / 100));
+
+ if (Math.abs(difference) > maxChangeAllowed) { // If this difference is too big, use the maximum allowed
+ // change
+ int change = maxChangeAllowed * (difference > 0 ? 1 : -1); // Make the change positive or negative.
+ this.lEUt += change; // Apply the change
+ } else {
+ this.lEUt = newPower;
+ }
+ if (this.lEUt <= 0) {
+ this.lEUt = 0;
+ this.mEfficiency = 0;
+ return CheckRecipeResultRegistry.NO_FUEL_FOUND;
+ } else {
+ this.mMaxProgresstime = 20;
+ this.mEfficiencyIncrease = 10;
+ // Overvoltage is handled inside the MultiBlockBase when pushing out to dynamos. no need to do it here.
+ // Play sounds (GT++ addition - GT multiblocks play no sounds)
+ enableAllTurbineHatches();
+ return CheckRecipeResultRegistry.GENERATING;
+ }
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ return CheckRecipeResultRegistry.NO_FUEL_FOUND;
+ }
+
+ @Override
+ long fluidIntoPower(ArrayList<FluidStack> aFluids, long aOptFlow, int aBaseEff, float[] flowMultipliers) {
+ if (aFluids.size() >= 1) {
+ aOptFlow *= 800; // CHANGED THINGS HERE, check recipe runs once per 20 ticks
+ int tEU = 0;
+
+ int actualOptimalFlow = 0;
+
+ FluidStack firstFuelType = new FluidStack(aFluids.get(0), 0); // Identify a SINGLE type of fluid to process.
+ // Doesn't matter which one. Ignore the rest!
+ int fuelValue = getFuelValue(firstFuelType);
+ actualOptimalFlow = GT_Utility
+ .safeInt((long) Math.ceil((double) aOptFlow * (double) flowMultipliers[2] / (double) fuelValue));
+ this.realOptFlow = actualOptimalFlow; // For scanner info
+
+ int remainingFlow = GT_Utility.safeInt((long) (actualOptimalFlow * 1.25f)); // Allowed to use up to 125% of
+ // optimal flow. Variable
+ // required outside of loop for
+ // multi-hatch scenarios.
+ int flow = 0;
+ int totalFlow = 0;
+
+ storedFluid = 0;
+ for (FluidStack aFluid : aFluids) {
+ if (aFluid.isFluidEqual(firstFuelType)) {
+ flow = Math.min(aFluid.amount, remainingFlow); // try to use up w/o exceeding remainingFlow
+ depleteInput(new FluidStack(aFluid, flow)); // deplete that amount
+ this.storedFluid += aFluid.amount;
+ remainingFlow -= flow; // track amount we're allowed to continue depleting from hatches
+ totalFlow += flow; // track total input used
+ }
+ }
+ String fn = FluidRegistry.getFluidName(firstFuelType);
+ String[] nameSegments = fn.split("\\.", 2);
+ if (nameSegments.length == 2) {
+ String outputName = nameSegments[1];
+ FluidStack output = FluidRegistry.getFluidStack(outputName, totalFlow);
+ if (output == null) {
+ output = FluidRegistry.getFluidStack("molten." + outputName, totalFlow);
+ }
+ if (output != null) {
+ addOutput(output);
+ }
+ }
+ if (totalFlow <= 0) return 0;
+ tEU = GT_Utility.safeInt((long) ((fuelValue / 20D) * (double) totalFlow));
+
+ if (totalFlow == actualOptimalFlow) {
+ tEU = GT_Utility.safeInt((long) (aBaseEff / 10000D * tEU));
+ } else {
+ double efficiency = 1.0D - Math.abs((totalFlow - actualOptimalFlow) / (float) actualOptimalFlow);
+
+ tEU = (int) (tEU * efficiency);
+ tEU = GT_Utility.safeInt((long) (aBaseEff / 10000D * tEU));
+ }
+
+ return tEU;
+ }
+ return 0;
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return 1;
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Large Plasma Turbine";
+ }
+
+ @Override
+ protected String getTurbineType() {
+ return "Plasma";
+ }
+
+ @Override
+ protected String getCasingName() {
+ return "Reinforced Plasma Turbine Casing";
+ }
+
+ @Override
+ protected ITexture getTextureFrontFace() {
+ return new GT_RenderedTexture(TexturesGtBlock.Overlay_Machine_Controller_Advanced);
+ }
+
+ @Override
+ protected ITexture getTextureFrontFaceActive() {
+ return new GT_RenderedTexture(TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active);
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GT_MTE_LargeTurbine_SCSteam.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GT_MTE_LargeTurbine_SCSteam.java
new file mode 100644
index 0000000000..7ee40757fd
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GT_MTE_LargeTurbine_SCSteam.java
@@ -0,0 +1,126 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production.turbines;
+
+import java.util.ArrayList;
+
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.fluids.FluidRegistry;
+import net.minecraftforge.fluids.FluidStack;
+
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.render.TextureFactory;
+import gregtech.api.util.GT_ModHandler;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.util.math.MathUtils;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GT_MTE_LargeTurbine_SCSteam extends GregtechMetaTileEntity_LargerTurbineBase {
+
+ public GT_MTE_LargeTurbine_SCSteam(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GT_MTE_LargeTurbine_SCSteam(String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GT_MTE_LargeTurbine_SCSteam(mName);
+ }
+
+ @Override
+ public int getCasingMeta() {
+ return 15;
+ }
+
+ @Override
+ public int getCasingTextureIndex() {
+ return 1538;
+ }
+
+ @Override
+ protected boolean requiresOutputHatch() {
+ return true;
+ }
+
+ @Override
+ public int getPollutionPerSecond(ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public int getFuelValue(FluidStack aLiquid) {
+ return 0;
+ }
+
+ @Override
+ long fluidIntoPower(ArrayList<FluidStack> aFluids, long aOptFlow, int aBaseEff, float[] flowMultipliers) {
+ int tEU = 0;
+ int totalFlow = 0; // Byproducts are based on actual flow
+ int flow = 0;
+ // Variable required outside of loop for
+ // multi-hatch scenarios.
+ this.realOptFlow = aOptFlow;
+ // this.realOptFlow = (double) aOptFlow * (double) flowMultipliers[0];
+ // Will there be an multiplier for SC?
+ int remainingFlow = MathUtils.safeInt((long) (realOptFlow * 1.25f)); // Allowed to use up to
+ // 125% of optimal flow.
+
+ storedFluid = 0;
+ FluidStack tSCSteam = FluidRegistry.getFluidStack("supercriticalsteam", 1);
+ for (int i = 0; i < aFluids.size() && remainingFlow > 0; i++) {
+ if (GT_Utility.areFluidsEqual(aFluids.get(i), tSCSteam, true)) {
+ flow = Math.min(aFluids.get(i).amount, remainingFlow); // try to use up w/o exceeding remainingFlow
+ depleteInput(new FluidStack(aFluids.get(i), flow)); // deplete that amount
+ this.storedFluid += aFluids.get(i).amount;
+ remainingFlow -= flow; // track amount we're allowed to continue depleting from hatches
+ totalFlow += flow; // track total input used
+ }
+ }
+ if (totalFlow <= 0) return 0;
+ tEU = totalFlow;
+ addOutput(GT_ModHandler.getSteam(totalFlow));
+ if (totalFlow != realOptFlow) {
+ float efficiency = 1.0f - Math.abs((totalFlow - (float) realOptFlow) / (float) realOptFlow);
+ // if(totalFlow>aOptFlow){efficiency = 1.0f;}
+ tEU *= efficiency;
+ tEU = Math.max(1, MathUtils.safeInt((long) tEU * (long) aBaseEff / 10000L));
+ } else {
+ tEU = MathUtils.safeInt((long) tEU * (long) aBaseEff / 10000L);
+ }
+
+ return tEU * 100L;
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return 8;
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Large Supercritical Steam Turbine";
+ }
+
+ @Override
+ protected String getTurbineType() {
+ return "Supercritical Steam";
+ }
+
+ @Override
+ protected String getCasingName() {
+ return "Reinforced SC Turbine Casing";
+ }
+
+ @Override
+ protected ITexture getTextureFrontFace() {
+ return TextureFactory.of(TexturesGtBlock.Overlay_Machine_Controller_Advanced);
+ }
+
+ @Override
+ protected ITexture getTextureFrontFaceActive() {
+ return TextureFactory.of(TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active);
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GT_MTE_LargeTurbine_SHSteam.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GT_MTE_LargeTurbine_SHSteam.java
new file mode 100644
index 0000000000..d1346d3a51
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GT_MTE_LargeTurbine_SHSteam.java
@@ -0,0 +1,204 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production.turbines;
+
+import java.util.ArrayList;
+
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.common.util.ForgeDirection;
+import net.minecraftforge.fluids.FluidStack;
+
+import gregtech.GT_Mod;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.objects.GT_RenderedTexture;
+import gregtech.api.util.GT_ModHandler;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.math.MathUtils;
+import gtPlusPlus.core.util.minecraft.PlayerUtils;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+@SuppressWarnings("deprecation")
+public class GT_MTE_LargeTurbine_SHSteam extends GregtechMetaTileEntity_LargerTurbineBase {
+
+ public boolean achievement = false;
+ private boolean looseFit = false;
+
+ public GT_MTE_LargeTurbine_SHSteam(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GT_MTE_LargeTurbine_SHSteam(String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GT_MTE_LargeTurbine_SHSteam(mName);
+ }
+
+ @Override
+ public int getCasingMeta() {
+ return 2;
+ }
+
+ @Override
+ public int getCasingTextureIndex() {
+ return 59;
+ }
+
+ @Override
+ protected boolean requiresOutputHatch() {
+ return true;
+ }
+
+ @Override
+ public int getPollutionPerSecond(ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public int getFuelValue(FluidStack aLiquid) {
+ return 0;
+ }
+
+ @Override
+ long fluidIntoPower(ArrayList<FluidStack> aFluids, long aOptFlow, int aBaseEff, float[] flowMultipliers) {
+ if (looseFit) {
+ aOptFlow *= 4;
+ if (aBaseEff > 10000) {
+ aOptFlow *= Math.pow(1.1f, ((aBaseEff - 7500) / 10000F) * 20f);
+ aBaseEff = 7500;
+ } else if (aBaseEff > 7500) {
+ aOptFlow *= Math.pow(1.1f, ((aBaseEff - 7500) / 10000F) * 20f);
+ aBaseEff *= 0.75f;
+ } else {
+ aBaseEff *= 0.75f;
+ }
+ }
+ // prevent overflow like that in SC Steam
+ long tEU = 0;
+ int totalFlow = 0; // Byproducts are based on actual flow
+ int flow = 0;
+
+ // Variable required outside of loop for
+ // multi-hatch scenarios.
+ this.realOptFlow = aOptFlow * flowMultipliers[0];
+
+ int remainingFlow = MathUtils.safeInt((long) (realOptFlow * 1.25f)); // Allowed to use up to
+ // 125% of optimal flow.
+
+ storedFluid = 0;
+ for (int i = 0; i < aFluids.size() && remainingFlow > 0; i++) {
+ String fluidName = aFluids.get(i)
+ .getFluid()
+ .getUnlocalizedName(aFluids.get(i));
+ if (fluidName.equals("ic2.fluidSuperheatedSteam")) {
+ flow = Math.min(aFluids.get(i).amount, remainingFlow); // try to use up w/o exceeding remainingFlow
+ depleteInput(new FluidStack(aFluids.get(i), flow)); // deplete that amount
+ this.storedFluid += aFluids.get(i).amount;
+ remainingFlow -= flow; // track amount we're allowed to continue depleting from hatches
+ totalFlow += flow; // track total input used
+ if (!achievement) {
+ try {
+ GT_Mod.achievements.issueAchievement(
+ this.getBaseMetaTileEntity()
+ .getWorld()
+ .getPlayerEntityByName(
+ this.getBaseMetaTileEntity()
+ .getOwnerName()),
+ "efficientsteam");
+ } catch (Exception e) {}
+ achievement = true;
+ }
+ } else if (fluidName.equals("fluid.steam") || fluidName.equals("ic2.fluidSteam")
+ || fluidName.equals("fluid.mfr.steam.still.name")) {
+ depleteInput(new FluidStack(aFluids.get(i), aFluids.get(i).amount));
+ }
+ }
+ if (totalFlow <= 0) return 0;
+ tEU = totalFlow;
+ addOutput(GT_ModHandler.getSteam(totalFlow));
+ if (totalFlow != realOptFlow) {
+ float efficiency = 1.0f - Math.abs((totalFlow - (float) realOptFlow) / (float) realOptFlow);
+ // if(totalFlow>aOptFlow){efficiency = 1.0f;}
+ tEU *= efficiency;
+ tEU = Math.max(1L, tEU * aBaseEff / 10000L);
+ } else {
+ tEU = tEU * aBaseEff / 10000L;
+ }
+
+ return tEU;
+ }
+
+ @Override
+ public void onModeChangeByScrewdriver(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+ // Using a screwdriver to change modes should allow for any combination of Slow/Fast and Tight/Loose Mode
+ // Whenever there's a mode switch, there will be two messages on the player chat
+ // The two messages specify which two modes the turbine is on after the change
+ // (Tight/Loose changes on every action, Slow/Fast changes every other action, all pairs are cycled this way)
+ if (side == getBaseMetaTileEntity().getFrontFacing()) {
+ looseFit ^= true;
+ GT_Utility.sendChatToPlayer(
+ aPlayer,
+ looseFit ? "Fitting is Loose (Higher Flow)" : "Fitting is Tight (Higher Efficiency)");
+ }
+
+ if (looseFit) {
+ super.onModeChangeByScrewdriver(side, aPlayer, aX, aY, aZ);
+ } else if (mFastMode) {
+ PlayerUtils.messagePlayer(aPlayer, "Running in Fast (48x) Mode.");
+ } else {
+ PlayerUtils.messagePlayer(aPlayer, "Running in Slow (16x) Mode.");
+ }
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return (looseFit && CORE.RANDOM.nextInt(4) == 0) ? 0 : 1;
+ }
+
+ @Override
+ public boolean isLooseMode() {
+ return looseFit;
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ super.saveNBTData(aNBT);
+ aNBT.setBoolean("turbineFitting", looseFit);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ looseFit = aNBT.getBoolean("turbineFitting");
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Large Super-heated Steam Turbine";
+ }
+
+ @Override
+ protected String getTurbineType() {
+ return "Super-heated Steam";
+ }
+
+ @Override
+ protected String getCasingName() {
+ return "Reinforced HP Steam Turbine Casing";
+ }
+
+ @Override
+ protected ITexture getTextureFrontFace() {
+ return new GT_RenderedTexture(TexturesGtBlock.Overlay_Machine_Controller_Advanced);
+ }
+
+ @Override
+ protected ITexture getTextureFrontFaceActive() {
+ return new GT_RenderedTexture(TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active);
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GT_MTE_LargeTurbine_Steam.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GT_MTE_LargeTurbine_Steam.java
new file mode 100644
index 0000000000..c882b84aab
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GT_MTE_LargeTurbine_Steam.java
@@ -0,0 +1,215 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production.turbines;
+
+import static gtPlusPlus.core.lib.CORE.RANDOM;
+
+import java.util.ArrayList;
+
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.common.util.ForgeDirection;
+import net.minecraftforge.fluids.FluidStack;
+
+import gregtech.GT_Mod;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.objects.GT_RenderedTexture;
+import gregtech.api.util.GT_ModHandler;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.util.math.MathUtils;
+import gtPlusPlus.core.util.minecraft.PlayerUtils;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+@SuppressWarnings("deprecation")
+public class GT_MTE_LargeTurbine_Steam extends GregtechMetaTileEntity_LargerTurbineBase {
+
+ private float water;
+ private boolean achievement = false;
+ private boolean looseFit = false;
+
+ public GT_MTE_LargeTurbine_Steam(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GT_MTE_LargeTurbine_Steam(String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GT_MTE_LargeTurbine_Steam(mName);
+ }
+
+ @Override
+ public int getCasingMeta() {
+ return 1;
+ }
+
+ @Override
+ public int getCasingTextureIndex() {
+ return 16;
+ }
+
+ @Override
+ protected boolean requiresOutputHatch() {
+ return true;
+ }
+
+ @Override
+ public int getPollutionPerSecond(ItemStack aStack) {
+ return 0;
+ }
+
+ private int useWater(float input) {
+ water = water + input;
+ int usage = (int) water;
+ water = water - usage;
+ return usage;
+ }
+
+ @Override
+ public int getFuelValue(FluidStack aLiquid) {
+ return 0;
+ }
+
+ @Override
+ long fluidIntoPower(ArrayList<FluidStack> aFluids, long aOptFlow, int aBaseEff, float[] flowMultipliers) {
+ if (looseFit) {
+ aOptFlow *= 4;
+ if (aBaseEff > 10000) {
+ aOptFlow *= Math.pow(1.1f, ((aBaseEff - 7500) / 10000F) * 20f);
+ aBaseEff = 7500;
+ } else if (aBaseEff > 7500) {
+ aOptFlow *= Math.pow(1.1f, ((aBaseEff - 7500) / 10000F) * 20f);
+ aBaseEff *= 0.75f;
+ } else {
+ aBaseEff *= 0.75f;
+ }
+ }
+ // prevent overflow like that in SC Steam
+ long tEU = 0;
+ int totalFlow = 0; // Byproducts are based on actual flow
+ int flow = 0;
+
+ // Variable required outside of loop for
+ // multi-hatch scenarios.
+ this.realOptFlow = aOptFlow * flowMultipliers[0];
+
+ int remainingFlow = MathUtils.safeInt((long) (realOptFlow * 1.25f)); // Allowed to
+ // use up to
+ // 125% of
+ // optimal flow.
+
+ storedFluid = 0;
+ for (int i = 0; i < aFluids.size() && remainingFlow > 0; i++) { // loop through each hatch; extract inputs and
+ // track totals.
+ String fluidName = aFluids.get(i)
+ .getFluid()
+ .getUnlocalizedName(aFluids.get(i));
+ if (fluidName.equals("fluid.steam") || fluidName.equals("ic2.fluidSteam")
+ || fluidName.equals("fluid.mfr.steam.still.name")) {
+ flow = Math.min(aFluids.get(i).amount, remainingFlow); // try to use up w/o exceeding remainingFlow
+ depleteInput(new FluidStack(aFluids.get(i), flow)); // deplete that amount
+ this.storedFluid += aFluids.get(i).amount;
+ remainingFlow -= flow; // track amount we're allowed to continue depleting from hatches
+ totalFlow += flow; // track total input used
+ if (!achievement) {
+ GT_Mod.achievements.issueAchievement(
+ this.getBaseMetaTileEntity()
+ .getWorld()
+ .getPlayerEntityByName(
+ this.getBaseMetaTileEntity()
+ .getOwnerName()),
+ "muchsteam");
+ achievement = true;
+ }
+ } else if (fluidName.equals("ic2.fluidSuperheatedSteam")) {
+ depleteInput(new FluidStack(aFluids.get(i), aFluids.get(i).amount));
+ }
+ }
+ if (totalFlow <= 0) return 0;
+ tEU = totalFlow;
+ int waterToOutput = useWater(totalFlow / 160.0f);
+ addOutput(GT_ModHandler.getDistilledWater(waterToOutput));
+ if (totalFlow != realOptFlow) {
+ float efficiency = 1.0f - Math.abs((totalFlow - (float) realOptFlow) / (float) realOptFlow);
+ // if(totalFlow>aOptFlow){efficiency = 1.0f;}
+ tEU *= efficiency;
+ tEU = Math.max(1L, tEU * aBaseEff / 20000L);
+ } else {
+ tEU = tEU * aBaseEff / 20000L;
+ }
+
+ return tEU;
+ }
+
+ @Override
+ public void onModeChangeByScrewdriver(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+ // Using a screwdriver to change modes should allow for any combination of Slow/Fast and Tight/Loose Mode
+ // Whenever there's a mode switch, there will be two messages on the player chat
+ // The two messages specify which two modes the turbine is on after the change
+ // (Tight/Loose changes on every action, Slow/Fast changes every other action, all pairs are cycled this way)
+ if (side == getBaseMetaTileEntity().getFrontFacing()) {
+ looseFit ^= true;
+ GT_Utility.sendChatToPlayer(
+ aPlayer,
+ looseFit ? "Fitting: Loose - More Flow" : "Fitting: Tight - More Efficiency");
+ }
+
+ if (looseFit) {
+ super.onModeChangeByScrewdriver(side, aPlayer, aX, aY, aZ);
+ } else if (mFastMode) {
+ PlayerUtils.messagePlayer(aPlayer, "Running in Fast (48x) Mode.");
+ } else {
+ PlayerUtils.messagePlayer(aPlayer, "Running in Slow (16x) Mode.");
+ }
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return (looseFit && RANDOM.nextInt(4) == 0) ? 0 : 1;
+ }
+
+ @Override
+ public boolean isLooseMode() {
+ return looseFit;
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ super.saveNBTData(aNBT);
+ aNBT.setBoolean("turbineFitting", looseFit);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+ looseFit = aNBT.getBoolean("turbineFitting");
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Large Steam Turbine";
+ }
+
+ @Override
+ protected String getTurbineType() {
+ return "Steam";
+ }
+
+ @Override
+ protected String getCasingName() {
+ return "Reinforced Steam Turbine Casing";
+ }
+
+ @Override
+ protected ITexture getTextureFrontFace() {
+ return new GT_RenderedTexture(TexturesGtBlock.Overlay_Machine_Controller_Advanced);
+ }
+
+ @Override
+ protected ITexture getTextureFrontFaceActive() {
+ return new GT_RenderedTexture(TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active);
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GregtechMetaTileEntity_LargerTurbineBase.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GregtechMetaTileEntity_LargerTurbineBase.java
new file mode 100644
index 0000000000..eec137cea2
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/turbines/GregtechMetaTileEntity_LargerTurbineBase.java
@@ -0,0 +1,893 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production.turbines;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.lazy;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static gregtech.api.enums.GT_HatchElement.Dynamo;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.InputHatch;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_HatchElement.Muffler;
+import static gregtech.api.enums.GT_HatchElement.OutputHatch;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+import static gregtech.api.util.GT_Utility.filterValidMTEs;
+import static gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase.GTPPHatchElement.TTDynamo;
+
+import java.util.ArrayList;
+
+import net.minecraft.block.Block;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.StatCollector;
+import net.minecraftforge.common.util.ForgeDirection;
+import net.minecraftforge.fluids.FluidStack;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits;
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+
+import gregtech.api.enums.Materials;
+import gregtech.api.enums.Textures;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.items.GT_MetaGenerated_Tool;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Dynamo;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_InputBus;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Muffler;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gregtech.api.util.shutdown.ShutDownReason;
+import gregtech.api.util.shutdown.ShutDownReasonRegistry;
+import gtPlusPlus.api.objects.Logger;
+import gtPlusPlus.api.objects.data.AutoMap;
+import gtPlusPlus.api.objects.minecraft.BlockPos;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.math.MathUtils;
+import gtPlusPlus.core.util.minecraft.PlayerUtils;
+import gtPlusPlus.core.util.minecraft.gregtech.PollutionUtils;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Turbine;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+
+public abstract class GregtechMetaTileEntity_LargerTurbineBase
+ extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_LargerTurbineBase> implements ISurvivalConstructable {
+
+ protected int baseEff = 0;
+ protected long optFlow = 0;
+ protected long euPerTurbine = 0;
+ protected double realOptFlow = 0;
+ protected int storedFluid = 0;
+ protected int counter = 0;
+ protected boolean mFastMode = false;
+ protected double mufflerReduction = 1;
+ protected float[] flowMultipliers = new float[] { 1, 1, 1 };
+
+ public ITexture frontFace;
+ public ITexture frontFaceActive;
+
+ public ArrayList<GT_MetaTileEntity_Hatch_Turbine> mTurbineRotorHatches = new ArrayList<>();
+
+ public GregtechMetaTileEntity_LargerTurbineBase(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ frontFace = getTextureFrontFace();
+ frontFaceActive = getTextureFrontFaceActive();
+ }
+
+ public GregtechMetaTileEntity_LargerTurbineBase(String aName) {
+ super(aName);
+ frontFace = getTextureFrontFace();
+ frontFaceActive = getTextureFrontFaceActive();
+ }
+
+ protected abstract ITexture getTextureFrontFace();
+
+ protected abstract ITexture getTextureFrontFaceActive();
+
+ protected abstract String getTurbineType();
+
+ protected abstract String getCasingName();
+
+ protected abstract boolean requiresOutputHatch();
+
+ @Override
+ protected final GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Controller Block for the XL " + getTurbineType() + " Turbine")
+ .addInfo("Runs as fast as 16 Large Turbines of the same type, takes the space of 12")
+ .addInfo("Right-click with screwdriver to enable Fast Mode, to run it even faster")
+ .addInfo("Optimal flow will increase or decrease accordingly on mode switch")
+ .addInfo("Fast Mode increases speed to 48x instead of 16x, with some penalties")
+ .addInfo("Maintenance problems and turbine damage happen 12x as often in Fast Mode");
+ if (getTurbineType().contains("Steam")) {
+ tt.addInfo("XL Steam Turbines can use Loose Mode with either Slow or Fast Mode");
+ }
+ if (getTurbineType().equals("Plasma")) {
+ tt.addInfo("Plasma fuel efficiency is lower for high tier turbines when using low-grade plasmas")
+ .addInfo("Efficiency = ((FuelValue / 200,000)^2) / (EU per Turbine)");
+ }
+ tt.addPollutionAmount(getPollutionPerSecond(null))
+ .addInfo("Pollution is 3x higher in Fast Mode")
+ .addSeparator()
+ .beginStructureBlock(7, 9, 7, false)
+ .addController("Top Middle")
+ .addCasingInfoMin(getCasingName(), 360, false)
+ .addCasingInfoMin("Rotor Shaft", 30, false)
+ .addOtherStructurePart("Rotor Assembly", "Any 1 dot hint", 1)
+ .addInputBus("Any 4 dot hint (min 1)", 4)
+ .addInputHatch("Any 4 dot hint(min 1)", 4);
+ if (requiresOutputHatch()) {
+ tt.addOutputHatch("Any 4 dot hint(min 1)", 4);
+ }
+ tt.addDynamoHatch("Any 4 dot hint(min 1)", 4)
+ .addMaintenanceHatch("Any 4 dot hint(min 1)", 4);
+ if (requiresMufflers()) {
+ tt.addMufflerHatch("Any 7 dot hint (x4)", 7);
+ }
+ tt.toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ private static final String STRUCTURE_PIECE_MAIN = "main";
+ private static final ClassValue<IStructureDefinition<GregtechMetaTileEntity_LargerTurbineBase>> STRUCTURE_DEFINITION = new ClassValue<>() {
+
+ @Override
+ @SuppressWarnings("SpellCheckingInspection")
+ protected IStructureDefinition<GregtechMetaTileEntity_LargerTurbineBase> computeValue(Class<?> type) {
+ return StructureDefinition.<GregtechMetaTileEntity_LargerTurbineBase>builder()
+ // c = turbine casing
+ // s = turbine shaft
+ // t = turbine housing
+ // h = dynamo/maint
+ // m = muffler
+ .addShape(
+ STRUCTURE_PIECE_MAIN,
+ (new String[][] { { "ccchccc", "ccccccc", "ccmmmcc", "ccm~mcc", "ccmmmcc", "ccccccc", "ccchccc" },
+ { "ctchctc", "cscccsc", "cscccsc", "cscccsc", "cscccsc", "cscccsc", "ctchctc" },
+ { "ccchccc", "ccccccc", "ccccccc", "ccccccc", "ccccccc", "ccccccc", "ccchccc" },
+ { "ccchccc", "ccccccc", "ccccccc", "ccccccc", "ccccccc", "ccccccc", "ccchccc" },
+ { "ctchctc", "cscccsc", "cscccsc", "cscccsc", "cscccsc", "cscccsc", "ctchctc" },
+ { "ccchccc", "ccccccc", "ccccccc", "ccccccc", "ccccccc", "ccccccc", "ccchccc" },
+ { "ccchccc", "ccccccc", "ccccccc", "ccccccc", "ccccccc", "ccccccc", "ccchccc" },
+ { "ctchctc", "cscccsc", "cscccsc", "cscccsc", "cscccsc", "cscccsc", "ctchctc" },
+ { "ccchccc", "ccccccc", "ccccccc", "ccccccc", "ccccccc", "ccccccc", "ccchccc" }, }))
+ .addElement('c', lazy(t -> ofBlock(t.getCasingBlock(), t.getCasingMeta())))
+ .addElement('s', lazy(t -> ofBlock(t.getShaftBlock(), t.getTurbineShaftMeta())))
+ .addElement(
+ 't',
+ lazy(
+ t -> buildHatchAdder(GregtechMetaTileEntity_LargerTurbineBase.class)
+ .adder(GregtechMetaTileEntity_LargerTurbineBase::addTurbineHatch)
+ .hatchClass(GT_MetaTileEntity_Hatch_Turbine.class)
+ .casingIndex(t.getCasingTextureIndex())
+ .dot(1)
+ .build()))
+ .addElement(
+ 'h',
+ lazy(
+ t -> buildHatchAdder(GregtechMetaTileEntity_LargerTurbineBase.class)
+ .atLeast(InputBus, InputHatch, OutputHatch, Dynamo.or(TTDynamo), Maintenance)
+ .casingIndex(t.getCasingTextureIndex())
+ .dot(4)
+ .buildAndChain(t.getCasingBlock(), t.getCasingMeta())))
+ .addElement(
+ 'm',
+ lazy(
+ t -> buildHatchAdder(GregtechMetaTileEntity_LargerTurbineBase.class).atLeast(Muffler)
+ .casingIndex(t.getCasingTextureIndex())
+ .dot(7)
+ .buildAndChain(t.getCasingBlock(), t.getCasingMeta())))
+ .build();
+ }
+ };
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_LargerTurbineBase> getStructureDefinition() {
+ return STRUCTURE_DEFINITION.get(getClass());
+ }
+
+ private boolean requiresMufflers() {
+ if (!PollutionUtils.isPollutionEnabled()) {
+ return false;
+ }
+ return getPollutionPerSecond(null) > 0;
+ }
+
+ public final double getMufflerReduction() {
+ double totalReduction = 0;
+ for (GT_MetaTileEntity_Hatch_Muffler tHatch : filterValidMTEs(mMufflerHatches)) {
+ totalReduction += ((double) tHatch.calculatePollutionReduction(100)) / 100;
+ }
+ return totalReduction / 4;
+ }
+
+ @Override
+ public void clearHatches() {
+ super.clearHatches();
+ mTurbineRotorHatches.clear();
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ // we do not check for casing count here. the bare minimal is 372 but we only require 360
+ boolean aStructure = checkPiece(STRUCTURE_PIECE_MAIN, 3, 3, 0);
+ log("Structure Check: " + aStructure);
+ if (mTurbineRotorHatches.size() != 12 || mMaintenanceHatches.size() != 1
+ || (mDynamoHatches.size() < 1 && mTecTechDynamoHatches.size() < 1)
+ || (requiresMufflers() && mMufflerHatches.size() != 4)
+ || mInputBusses.size() < 1
+ || mInputHatches.size() < 1
+ || (requiresOutputHatch() && mOutputHatches.size() < 1)) {
+ log(
+ "Bad Hatches - Turbine Housings: " + mTurbineRotorHatches.size()
+ + ", Maint: "
+ + mMaintenanceHatches.size()
+ + ", Dynamo: "
+ + mDynamoHatches.size()
+ + ", Muffler: "
+ + mMufflerHatches.size()
+ + ", Input Buses: "
+ + mInputBusses.size()
+ + ", Input Hatches: "
+ + mInputHatches.size()
+ + ", Output Hatches: "
+ + mOutputHatches.size());
+ return false;
+ }
+ mufflerReduction = getMufflerReduction();
+ return aStructure;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(STRUCTURE_PIECE_MAIN, stackSize, hintsOnly, 3, 3, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ int realBudget = elementBudget >= 200 ? elementBudget : Math.min(200, elementBudget * 2);
+ return survivialBuildPiece(STRUCTURE_PIECE_MAIN, stackSize, 3, 3, 0, realBudget, env, false, true);
+ }
+
+ public boolean addTurbineHatch(final IGregTechTileEntity aTileEntity, final int aBaseCasingIndex) {
+ if (aTileEntity == null) {
+ return false;
+ }
+ final IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+ if (aMetaTileEntity == null) {
+ return false;
+ }
+ if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Turbine aTurbineHatch) {
+ log("Found GT_MetaTileEntity_Hatch_Turbine");
+ updateTexture(aTileEntity, aBaseCasingIndex);
+ IGregTechTileEntity g = this.getBaseMetaTileEntity();
+ if (aTurbineHatch.setController(new BlockPos(g.getXCoord(), g.getYCoord(), g.getZCoord(), g.getWorld()))) {
+ boolean aDidAdd = this.mTurbineRotorHatches.add(aTurbineHatch);
+ Logger.INFO("Injected Controller into Turbine Assembly. Found: " + this.mTurbineRotorHatches.size());
+ return aDidAdd;
+ } else {
+ Logger.INFO("Failed to inject controller into Turbine Assembly Hatch.");
+ }
+ }
+ log("Bad Turbine Housing");
+ return false;
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(ItemStack aStack) {
+ return getMaxEfficiency(aStack) > 0;
+ }
+
+ public Block getCasingBlock() {
+ return ModBlocks.blockSpecialMultiCasings;
+ }
+
+ public final Block getShaftBlock() {
+ return ModBlocks.blockSpecialMultiCasings;
+ }
+
+ public abstract int getCasingMeta();
+
+ public byte getTurbineShaftMeta() {
+ return 0;
+ }
+
+ public abstract int getCasingTextureIndex();
+
+ public abstract int getFuelValue(FluidStack aLiquid);
+
+ public static boolean isValidTurbine(ItemStack aTurbine) {
+ return (aTurbine != null && aTurbine.getItem() instanceof GT_MetaGenerated_Tool
+ && aTurbine.getItemDamage() >= 170
+ && aTurbine.getItemDamage() <= 176);
+ }
+
+ protected ArrayList<ItemStack> getAllBufferedTurbines() {
+ startRecipeProcessing();
+ ArrayList<ItemStack> aTurbinesInStorage = new ArrayList<>();
+ for (ItemStack aStack : getStoredInputs()) {
+ if (isValidTurbine(aStack)) {
+ int stackSize = aStack.stackSize;
+ while (stackSize > 0) {
+ int tmpStackSize = Math.min(stackSize, aStack.getMaxStackSize());
+ ItemStack copy = aStack.copy();
+ copy.stackSize = tmpStackSize;
+ aTurbinesInStorage.add(copy);
+ stackSize -= tmpStackSize;
+ }
+ }
+ }
+ endRecipeProcessing();
+ return aTurbinesInStorage;
+ }
+
+ public boolean areAllTurbinesTheSame() {
+ ArrayList<GT_MetaTileEntity_Hatch_Turbine> aTurbineAssemblies = getFullTurbineAssemblies();
+ if (aTurbineAssemblies.size() < 12) {
+ log("Found " + aTurbineAssemblies.size() + ", expected 12.");
+ return false;
+ }
+ AutoMap<Materials> aTurbineMats = new AutoMap<>();
+ AutoMap<Integer> aTurbineSizes = new AutoMap<>();
+ for (GT_MetaTileEntity_Hatch_Turbine aHatch : aTurbineAssemblies) {
+ aTurbineMats.add(GT_MetaGenerated_Tool.getPrimaryMaterial(aHatch.getTurbine()));
+ aTurbineSizes.add(getTurbineSize(aHatch.getTurbine()));
+ }
+ Materials aBaseMat = aTurbineMats.get(0);
+ int aBaseSize = aTurbineSizes.get(0);
+ for (int aSize : aTurbineSizes) {
+ if (aBaseSize != aSize) {
+ return false;
+ }
+ }
+ for (Materials aMat : aTurbineMats) {
+ if (aBaseMat != aMat) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static int getTurbineSize(ItemStack aTurbine) {
+ if (isValidTurbine(aTurbine)) {
+ if (aTurbine.getItemDamage() >= 170 && aTurbine.getItemDamage() < 172) {
+ return 1;
+ } else if (aTurbine.getItemDamage() >= 172 && aTurbine.getItemDamage() < 174) {
+ return 2;
+ } else if (aTurbine.getItemDamage() >= 174 && aTurbine.getItemDamage() < 176) {
+ return 3;
+ } else if (aTurbine.getItemDamage() >= 176 && aTurbine.getItemDamage() < 178) {
+ return 4;
+ }
+ }
+ return 0;
+ }
+
+ public static String getTurbineSizeString(int aSize) {
+ return switch (aSize) {
+ case 1 -> "Small Turbine";
+ case 2 -> "Turbine";
+ case 3 -> "Large Turbine";
+ case 4 -> "Huge Turbine";
+ default -> "";
+ };
+ }
+
+ protected ArrayList<GT_MetaTileEntity_Hatch_Turbine> getEmptyTurbineAssemblies() {
+ ArrayList<GT_MetaTileEntity_Hatch_Turbine> aEmptyTurbineRotorHatches = new ArrayList<>();
+ // log("Checking "+mTurbineRotorHatches.size()+" Assemblies for empties.");
+ for (GT_MetaTileEntity_Hatch_Turbine aTurbineHatch : this.mTurbineRotorHatches) {
+ if (!aTurbineHatch.hasTurbine()) {
+ aEmptyTurbineRotorHatches.add(aTurbineHatch);
+ }
+ }
+ return aEmptyTurbineRotorHatches;
+ }
+
+ protected ArrayList<GT_MetaTileEntity_Hatch_Turbine> getFullTurbineAssemblies() {
+ ArrayList<GT_MetaTileEntity_Hatch_Turbine> aTurbineRotorHatches = new ArrayList<>();
+ // log("Checking "+mTurbineRotorHatches.size()+" Assemblies for Turbines.");
+ for (GT_MetaTileEntity_Hatch_Turbine aTurbineHatch : this.mTurbineRotorHatches) {
+ if (aTurbineHatch.hasTurbine()) {
+ // log("Found Assembly with Turbine.");
+ aTurbineRotorHatches.add(aTurbineHatch);
+ }
+ }
+ return aTurbineRotorHatches;
+ }
+
+ protected void depleteTurbineFromStock(ItemStack aTurbine) {
+ if (aTurbine == null) {
+ return;
+ }
+ startRecipeProcessing();
+ for (GT_MetaTileEntity_Hatch_InputBus aInputBus : this.mInputBusses) {
+ for (int slot = aInputBus.getSizeInventory() - 1; slot >= 0; slot--) {
+ ItemStack aStack = aInputBus.getStackInSlot(slot);
+ if (aStack != null && GT_Utility.areStacksEqual(aStack, aTurbine)) {
+ aStack.stackSize -= aTurbine.stackSize;
+ updateSlots();
+ endRecipeProcessing();
+ return;
+ }
+ }
+ }
+ endRecipeProcessing();
+ }
+
+ @Override
+ public @NotNull CheckRecipeResult checkProcessing() {
+ try {
+ ArrayList<GT_MetaTileEntity_Hatch_Turbine> aEmptyTurbineRotorHatches = getEmptyTurbineAssemblies();
+ if (aEmptyTurbineRotorHatches.size() > 0) {
+ hatch: for (GT_MetaTileEntity_Hatch_Turbine aHatch : aEmptyTurbineRotorHatches) {
+ ArrayList<ItemStack> aTurbines = getAllBufferedTurbines();
+ for (ItemStack aTurbineItem : aTurbines) {
+ if (aTurbineItem == null) {
+ continue;
+ }
+ if (aHatch.insertTurbine(aTurbineItem.copy())) {
+ depleteTurbineFromStock(aTurbineItem);
+ continue hatch;
+ }
+ }
+ }
+ }
+
+ if (getEmptyTurbineAssemblies().size() > 0 || !areAllTurbinesTheSame()) {
+ stopMachine(ShutDownReasonRegistry.NO_TURBINE);
+ return CheckRecipeResultRegistry.NO_TURBINE_FOUND;
+ }
+
+ ArrayList<FluidStack> tFluids = getStoredFluids();
+
+ if (tFluids.size() > 0) {
+ if (baseEff == 0 || optFlow == 0
+ || counter >= 512
+ || this.getBaseMetaTileEntity()
+ .hasWorkJustBeenEnabled()
+ || this.getBaseMetaTileEntity()
+ .hasInventoryBeenModified()) {
+ counter = 0;
+ float aTotalBaseEff = 0;
+ float aTotalOptimalFlow = 0;
+
+ ItemStack aStack = getFullTurbineAssemblies().get(0)
+ .getTurbine();
+ aTotalBaseEff += GT_Utility.safeInt(
+ (long) ((5F + ((GT_MetaGenerated_Tool) aStack.getItem()).getToolCombatDamage(aStack)) * 1000F));
+ aTotalOptimalFlow += GT_Utility.safeInt(
+ (long) Math.max(
+ Float.MIN_NORMAL,
+ ((GT_MetaGenerated_Tool) aStack.getItem()).getToolStats(aStack)
+ .getSpeedMultiplier() * GT_MetaGenerated_Tool.getPrimaryMaterial(aStack).mToolSpeed
+ * 50)
+ * getSpeedMultiplier());
+ if (aTotalOptimalFlow < 0) {
+ aTotalOptimalFlow = 100;
+ }
+
+ flowMultipliers[0] = GT_MetaGenerated_Tool.getPrimaryMaterial(aStack).mSteamMultiplier;
+ flowMultipliers[1] = GT_MetaGenerated_Tool.getPrimaryMaterial(aStack).mGasMultiplier;
+ flowMultipliers[2] = GT_MetaGenerated_Tool.getPrimaryMaterial(aStack).mPlasmaMultiplier;
+ baseEff = MathUtils.roundToClosestInt(aTotalBaseEff);
+ optFlow = MathUtils.roundToClosestInt(aTotalOptimalFlow);
+ if (optFlow <= 0 || baseEff <= 0) {
+ stopMachine(ShutDownReasonRegistry.NONE); // in case the turbine got removed
+ return CheckRecipeResultRegistry.NO_FUEL_FOUND;
+ }
+ } else {
+ counter++;
+ }
+ }
+
+ // How much the turbine should be producing with this flow
+ long newPower = fluidIntoPower(tFluids, optFlow, baseEff, flowMultipliers);
+ long difference = newPower - this.lEUt; // difference between current output and new output
+
+ // Magic numbers: can always change by at least 10 eu/t, but otherwise by at most 1 percent of the
+ // difference in power level (per tick)
+ // This is how much the turbine can actually change during this tick
+ int maxChangeAllowed = Math.max(10, GT_Utility.safeInt(Math.abs(difference) / 100));
+
+ if (Math.abs(difference) > maxChangeAllowed) { // If this difference is too big, use the maximum allowed
+ // change
+ int change = maxChangeAllowed * (difference > 0 ? 1 : -1); // Make the change positive or negative.
+ this.lEUt += change; // Apply the change
+ } else {
+ this.lEUt = newPower;
+ }
+ if (this.lEUt <= 0) {
+ this.lEUt = 0;
+ this.mEfficiency = 0;
+ return CheckRecipeResultRegistry.NO_FUEL_FOUND;
+ } else {
+ this.mMaxProgresstime = 1;
+ this.mEfficiencyIncrease = 10;
+ // Overvoltage is handled inside the MultiBlockBase when pushing out to dynamos. no need to do it here.
+ // Play sounds (GT++ addition - GT multiblocks play no sounds)
+ enableAllTurbineHatches();
+ return CheckRecipeResultRegistry.GENERATING;
+ }
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ return CheckRecipeResultRegistry.NO_FUEL_FOUND;
+ }
+
+ @Override
+ public boolean doRandomMaintenanceDamage() {
+ if (getMaxParallelRecipes() == 0) {
+ stopMachine(ShutDownReasonRegistry.NO_TURBINE);
+ return false;
+ }
+
+ if (mRuntime++ > 1000) {
+ mRuntime = 0;
+
+ if (getBaseMetaTileEntity().getRandomNumber(6000) < getMaintenanceThreshold()) {
+ switch (getBaseMetaTileEntity().getRandomNumber(6)) {
+ case 0 -> mWrench = false;
+ case 1 -> mScrewdriver = false;
+ case 2 -> mSoftHammer = false;
+ case 3 -> mHardHammer = false;
+ case 4 -> mSolderingTool = false;
+ case 5 -> mCrowbar = false;
+ }
+ }
+ for (GT_MetaTileEntity_Hatch_Turbine aHatch : getFullTurbineAssemblies()) {
+ // This cycle depletes durability from the turbine rotors.
+ // The amount of times it is run depends on turbineDamageMultiplier
+ // In XL turbines, durability loss is around 5.2-5.3x faster than in singles
+ // To compensate for that, the mEU/t scaling is divided by 5 to make it only slightly faster
+ for (int i = 0; i < getTurbineDamageMultiplier(); i++) {
+ aHatch.damageTurbine(lEUt / 5, damageFactorLow, damageFactorHigh);
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return (getFullTurbineAssemblies().size());
+ }
+
+ abstract long fluidIntoPower(ArrayList<FluidStack> aFluids, long aOptFlow, int aBaseEff, float[] flowMultipliers);
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return 1;
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack aStack) {
+ return this.getMaxParallelRecipes() == 12 ? 10000 : 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(ItemStack aStack) {
+ return false;
+ }
+
+ public boolean isLooseMode() {
+ return false;
+ }
+
+ @Override
+ public String[] getExtraInfoData() {
+ int mPollutionReduction = (int) (100 * mufflerReduction);
+
+ String tRunning = mMaxProgresstime > 0
+ ? EnumChatFormatting.GREEN + StatCollector.translateToLocal("GT5U.turbine.running.true")
+ + EnumChatFormatting.RESET
+ : EnumChatFormatting.RED + StatCollector.translateToLocal("GT5U.turbine.running.false")
+ + EnumChatFormatting.RESET;
+
+ String tMaintenance = getIdealStatus() == getRepairStatus()
+ ? EnumChatFormatting.GREEN + StatCollector.translateToLocal("GT5U.turbine.maintenance.false")
+ + EnumChatFormatting.RESET
+ : EnumChatFormatting.RED + StatCollector.translateToLocal("GT5U.turbine.maintenance.true")
+ + EnumChatFormatting.RESET;
+ int tDura;
+
+ StringBuilder aTurbineDamage = new StringBuilder();
+ for (GT_MetaTileEntity_Hatch_Turbine aHatch : this.getFullTurbineAssemblies()) {
+ ItemStack aTurbine = aHatch.getTurbine();
+ tDura = MathUtils.safeInt(
+ (long) (100.0f / GT_MetaGenerated_Tool.getToolMaxDamage(aTurbine)
+ * (GT_MetaGenerated_Tool.getToolDamage(aTurbine)) + 1));
+ aTurbineDamage.append(EnumChatFormatting.RED)
+ .append(GT_Utility.formatNumbers(tDura))
+ .append(EnumChatFormatting.RESET)
+ .append("% | ");
+ }
+
+ long storedEnergy = 0;
+ long maxEnergy = 0;
+ for (GT_MetaTileEntity_Hatch_Dynamo tHatch : filterValidMTEs(mDynamoHatches)) {
+ storedEnergy += tHatch.getBaseMetaTileEntity()
+ .getStoredEU();
+ maxEnergy += tHatch.getBaseMetaTileEntity()
+ .getEUCapacity();
+ }
+
+ boolean aIsSteam = this.getClass()
+ .getName()
+ .toLowerCase()
+ .contains("steam");
+
+ String[] ret = new String[] {
+ // 8 Lines available for information panels
+ tRunning + ": "
+ + EnumChatFormatting.RED
+ + GT_Utility.formatNumbers(((lEUt * mEfficiency) / 10000))
+ + EnumChatFormatting.RESET
+ + " EU/t",
+ tMaintenance,
+ StatCollector.translateToLocal("GT5U.turbine.efficiency") + ": "
+ + EnumChatFormatting.YELLOW
+ + GT_Utility.formatNumbers((mEfficiency / 100F))
+ + EnumChatFormatting.RESET
+ + "%",
+ StatCollector.translateToLocal("GT5U.multiblock.energy") + ": "
+ + EnumChatFormatting.GREEN
+ + GT_Utility.formatNumbers(storedEnergy)
+ + EnumChatFormatting.RESET
+ + " EU / "
+ + EnumChatFormatting.YELLOW
+ + GT_Utility.formatNumbers(maxEnergy)
+ + EnumChatFormatting.RESET
+ + " EU",
+ StatCollector.translateToLocal("GT5U.turbine.flow") + ": "
+ + EnumChatFormatting.YELLOW
+ + GT_Utility.formatNumbers(MathUtils.safeInt((long) realOptFlow))
+ + EnumChatFormatting.RESET
+ + " L/s"
+ + EnumChatFormatting.YELLOW
+ + " ("
+ + (isLooseMode() ? StatCollector.translateToLocal("GT5U.turbine.loose")
+ : StatCollector.translateToLocal("GT5U.turbine.tight"))
+ + ")",
+ StatCollector.translateToLocal("GT5U.turbine.fuel") + ": "
+ + EnumChatFormatting.GOLD
+ + GT_Utility.formatNumbers(storedFluid)
+ + EnumChatFormatting.RESET
+ + "L",
+ StatCollector.translateToLocal("GT5U.turbine.dmg") + ": " + aTurbineDamage,
+ StatCollector.translateToLocal("GT5U.multiblock.pollution") + ": "
+ + EnumChatFormatting.GREEN
+ + GT_Utility.formatNumbers(mPollutionReduction)
+ + EnumChatFormatting.RESET
+ + " %" };
+ if (!aIsSteam) ret[4] = StatCollector.translateToLocal("GT5U.turbine.flow") + ": "
+ + EnumChatFormatting.YELLOW
+ + GT_Utility.formatNumbers(MathUtils.safeInt((long) realOptFlow))
+ + EnumChatFormatting.RESET
+ + " L/t";
+ return ret;
+ }
+
+ @Override
+ public boolean isGivingInformation() {
+ return true;
+ }
+
+ @Override
+ public boolean polluteEnvironment(int aPollutionLevel) {
+ if (this.requiresMufflers()) {
+ mPollution += aPollutionLevel * getPollutionMultiplier() * mufflerReduction;
+ for (GT_MetaTileEntity_Hatch_Muffler tHatch : filterValidMTEs(mMufflerHatches)) {
+ if (mPollution >= 10000) {
+ if (PollutionUtils.addPollution(this.getBaseMetaTileEntity(), 10000)) {
+ mPollution -= 10000;
+ }
+ } else {
+ break;
+ }
+ }
+ return mPollution < 10000;
+ }
+ return true;
+ }
+
+ @Override
+ public long maxAmperesOut() {
+ // This should not be a hard limit, due to TecTech dynamos
+ if (mFastMode) {
+ return 64;
+ } else {
+ return 16;
+ }
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ aNBT.setBoolean("mFastMode", mFastMode);
+ super.saveNBTData(aNBT);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ mFastMode = aNBT.getBoolean("mFastMode");
+ super.loadNBTData(aNBT);
+ }
+
+ @Override
+ public void onModeChangeByScrewdriver(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+ mFastMode = !mFastMode;
+ if (mFastMode) {
+ PlayerUtils.messagePlayer(aPlayer, "Running in Fast (48x) Mode.");
+ } else {
+ PlayerUtils.messagePlayer(aPlayer, "Running in Slow (16x) Mode.");
+ }
+ }
+
+ public final ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side,
+ ForgeDirection facing, int aColorIndex, boolean aActive, boolean aRedstone) {
+ return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[1][aColorIndex + 1],
+ facing == side ? getFrontFacingTurbineTexture(aActive)
+ : Textures.BlockIcons.getCasingTextureForId(getCasingTextureIndex()) };
+ }
+
+ protected ITexture getFrontFacingTurbineTexture(boolean isActive) {
+ if (isActive) {
+ return frontFaceActive;
+ }
+ return frontFace;
+ }
+
+ @Override
+ public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {
+ super.onPostTick(aBaseMetaTileEntity, aTick);
+ if (aBaseMetaTileEntity.isServerSide()) {
+ if (this.maxProgresstime() > 0 || this.getBaseMetaTileEntity()
+ .hasWorkJustBeenEnabled()) {
+ enableAllTurbineHatches();
+ }
+ if (this.maxProgresstime() <= 0) {
+ stopMachine(ShutDownReasonRegistry.NONE);
+ }
+ }
+ }
+
+ @Override
+ public void stopMachine(@NotNull ShutDownReason reason) {
+ baseEff = 0;
+ optFlow = 0;
+ disableAllTurbineHatches();
+ super.stopMachine(reason);
+ }
+
+ @Override
+ public void onRemoval() {
+ super.onRemoval();
+ for (GT_MetaTileEntity_Hatch_Turbine h : this.mTurbineRotorHatches) {
+ h.clearController();
+ }
+ disableAllTurbineHatches();
+ this.mTurbineRotorHatches.clear();
+ }
+
+ public void enableAllTurbineHatches() {
+ updateTurbineHatches(this.isMachineRunning());
+ }
+
+ public void disableAllTurbineHatches() {
+ updateTurbineHatches(false);
+ }
+
+ private Long mLastHatchUpdate;
+
+ public void updateTurbineHatches(boolean aState) {
+ if (mLastHatchUpdate == null) {
+ mLastHatchUpdate = System.currentTimeMillis() / 1000;
+ }
+ if (this.mTurbineRotorHatches.isEmpty() || ((System.currentTimeMillis() / 1000) - mLastHatchUpdate) <= 2) {
+ return;
+ }
+ for (GT_MetaTileEntity_Hatch_Turbine h : filterValidMTEs(this.mTurbineRotorHatches)) {
+ h.setActive(aState);
+ }
+
+ mLastHatchUpdate = System.currentTimeMillis() / 1000;
+ }
+
+ @Override
+ protected IAlignmentLimits getInitialAlignmentLimits() {
+ return (d, r, f) -> d == ForgeDirection.UP;
+ }
+
+ /**
+ * Called every tick the Machine runs
+ */
+ @Override
+ public boolean onRunningTick(ItemStack aStack) {
+ if (lEUt > 0) {
+ addEnergyOutput((lEUt * mEfficiency) / 10000);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean addEnergyOutput(long aEU) {
+ if (aEU <= 0) {
+ return true;
+ }
+ if (this.mAllDynamoHatches.size() > 0) {
+ return addEnergyOutputMultipleDynamos(aEU, true);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean addEnergyOutputMultipleDynamos(long aEU, boolean aAllowMixedVoltageDynamos) {
+ int injected = 0;
+ long aFirstVoltageFound = -1;
+ for (GT_MetaTileEntity_Hatch aDynamo : filterValidMTEs(mAllDynamoHatches)) {
+ long aVoltage = aDynamo.maxEUOutput();
+ // Check against voltage to check when hatch mixing
+ if (aFirstVoltageFound == -1) {
+ aFirstVoltageFound = aVoltage;
+ }
+ }
+
+ long leftToInject;
+ long aVoltage;
+ int aAmpsToInject;
+ int aRemainder;
+ int ampsOnCurrentHatch;
+ for (GT_MetaTileEntity_Hatch aDynamo : filterValidMTEs(mAllDynamoHatches)) {
+ leftToInject = aEU - injected;
+ aVoltage = aDynamo.maxEUOutput();
+ aAmpsToInject = (int) (leftToInject / aVoltage);
+ aRemainder = (int) (leftToInject - (aAmpsToInject * aVoltage));
+ ampsOnCurrentHatch = (int) Math.min(aDynamo.maxAmperesOut(), aAmpsToInject);
+
+ // add full amps
+ aDynamo.getBaseMetaTileEntity()
+ .increaseStoredEnergyUnits(aVoltage * ampsOnCurrentHatch, false);
+ injected += aVoltage * ampsOnCurrentHatch;
+
+ // add reminder
+ if (aRemainder > 0 && ampsOnCurrentHatch < aDynamo.maxAmperesOut()) {
+ aDynamo.getBaseMetaTileEntity()
+ .increaseStoredEnergyUnits(aRemainder, false);
+ injected += aRemainder;
+ }
+ }
+ return injected > 0;
+ }
+
+ public int getSpeedMultiplier() {
+ return mFastMode ? 48 : 16;
+ }
+
+ public int getMaintenanceThreshold() {
+ return mFastMode ? 12 : 1;
+ }
+
+ public int getPollutionMultiplier() {
+ return mFastMode ? 3 : 1;
+ }
+
+ public int getTurbineDamageMultiplier() {
+ return mFastMode ? 3 : 1;
+ }
+
+ @Override
+ public boolean supportsBatchMode() {
+ return false;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/storage/GregtechMetaTileEntity_PowerSubStationController.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/storage/GregtechMetaTileEntity_PowerSubStationController.java
new file mode 100644
index 0000000000..67244cb399
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/storage/GregtechMetaTileEntity_PowerSubStationController.java
@@ -0,0 +1,939 @@
+package gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.storage;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.onlyIf;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.withChannel;
+import static gregtech.api.enums.GT_HatchElement.Dynamo;
+import static gregtech.api.enums.GT_HatchElement.Energy;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.Mods.TecTech;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+import static gregtech.api.util.GT_StructureUtility.ofHatchAdderOptional;
+import static gregtech.api.util.GT_Utility.filterValidMTEs;
+import static gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase.GTPPHatchElement.TTDynamo;
+import static gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase.GTPPHatchElement.TTEnergy;
+
+import javax.annotation.Nullable;
+
+import net.minecraft.block.Block;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.world.World;
+import net.minecraftforge.common.util.Constants.NBT;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.gtnewhorizon.structurelib.StructureLibAPI;
+import com.gtnewhorizon.structurelib.alignment.constructable.ChannelDataAccessor;
+import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
+import com.gtnewhorizon.structurelib.structure.AutoPlaceEnvironment;
+import com.gtnewhorizon.structurelib.structure.IStructureDefinition;
+import com.gtnewhorizon.structurelib.structure.IStructureElement;
+import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment;
+import com.gtnewhorizon.structurelib.structure.StructureDefinition;
+import com.gtnewhorizon.structurelib.structure.StructureUtility;
+import com.gtnewhorizons.modularui.api.NumberFormatMUI;
+import com.gtnewhorizons.modularui.api.drawable.Text;
+import com.gtnewhorizons.modularui.api.forge.PlayerMainInvWrapper;
+import com.gtnewhorizons.modularui.api.screen.ModularWindow;
+import com.gtnewhorizons.modularui.api.screen.UIBuildContext;
+import com.gtnewhorizons.modularui.common.widget.DrawableWidget;
+import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget;
+import com.gtnewhorizons.modularui.common.widget.ProgressBar;
+import com.gtnewhorizons.modularui.common.widget.SlotGroup;
+import com.gtnewhorizons.modularui.common.widget.SlotWidget;
+import com.gtnewhorizons.modularui.common.widget.TextWidget;
+
+import gregtech.api.enums.GT_Values;
+import gregtech.api.enums.TAE;
+import gregtech.api.enums.Textures;
+import gregtech.api.gui.modularui.GT_UIInfos;
+import gregtech.api.gui.modularui.GT_UITextures;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.metatileentity.MetaTileEntity;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Dynamo;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Energy;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Maintenance;
+import gregtech.api.objects.GT_RenderedTexture;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.SimpleCheckRecipeResult;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.api.objects.Logger;
+import gtPlusPlus.core.block.ModBlocks;
+import gtPlusPlus.core.lib.CORE;
+import gtPlusPlus.core.util.MovingAverageLong;
+import gtPlusPlus.core.util.Utils;
+import gtPlusPlus.core.util.math.MathUtils;
+import gtPlusPlus.core.util.minecraft.PlayerUtils;
+import gtPlusPlus.preloader.asm.AsmConfig;
+import gtPlusPlus.xmod.gregtech.api.gui.GTPP_UITextures;
+import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase;
+
+public class GregtechMetaTileEntity_PowerSubStationController extends
+ GregtechMeta_MultiBlockBase<GregtechMetaTileEntity_PowerSubStationController> implements ISurvivalConstructable {
+
+ private static enum TopState {
+ MayBeTop,
+ Top,
+ NotTop
+ }
+
+ protected long mAverageEuUsage = 0;
+ protected final MovingAverageLong mAverageEuAdded = new MovingAverageLong(20);
+ protected final MovingAverageLong mAverageEuConsumed = new MovingAverageLong(20);
+ protected long mTotalEnergyAdded = 0;
+ protected long mTotalEnergyConsumed = 0;
+ protected long mTotalEnergyLost = 0;
+ protected boolean mIsOutputtingPower = false;
+ protected long mBatteryCapacity = 0;
+
+ private final int ENERGY_TAX = 5;
+
+ private int mCasing;
+ private int[] cellCount = new int[6];
+ private TopState topState = TopState.MayBeTop;
+ private static IStructureDefinition<GregtechMetaTileEntity_PowerSubStationController> STRUCTURE_DEFINITION = null;
+
+ public GregtechMetaTileEntity_PowerSubStationController(final int aID, final String aName,
+ final String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GregtechMetaTileEntity_PowerSubStationController(final String aName) {
+ super(aName);
+ }
+
+ @Override
+ public String getMachineType() {
+ return "Energy Buffer";
+ }
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+ tt.addMachineType(getMachineType())
+ .addInfo("Consumes " + this.ENERGY_TAX + "% of the average voltage of all energy type hatches")
+ .addInfo("Does not require maintenance")
+ .addInfo(
+ "Can be built with variable height between " + (CELL_HEIGHT_MIN + 2) + "-" + (CELL_HEIGHT_MAX + 2) + "")
+ .addInfo("Hatches can be placed nearly anywhere")
+ .addInfo("HV Energy/Dynamo Hatches are the lowest tier you can use")
+ .addInfo("Supports voltages >= UHV using MAX tier components.")
+ .addSeparator()
+ .addController("Bottom Center")
+ .addCasingInfoMin("Sub-Station External Casings", 10, false)
+ .addDynamoHatch("Any Casing", 1)
+ .addEnergyHatch("Any Casing", 1)
+ .addSubChannelUsage("capacitor", "Vanadium Capacitor Cell Tier")
+ .addSubChannelUsage("height", "Height of structure")
+ .toolTipFinisher(CORE.GT_Tooltip_Builder.get());
+ return tt;
+ }
+
+ @Override
+ public ITexture[] getTexture(final IGregTechTileEntity aBaseMetaTileEntity, final ForgeDirection side,
+ final ForgeDirection facing, final int aColorIndex, final boolean aActive, final boolean aRedstone) {
+ if (side == facing) {
+ return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(TAE.GTPP_INDEX(24)),
+ new GT_RenderedTexture(
+ aActive ? Textures.BlockIcons.OVERLAY_FRONT_DISASSEMBLER_ACTIVE
+ : Textures.BlockIcons.OVERLAY_FRONT_DISASSEMBLER) };
+ }
+ if (side == this.getBaseMetaTileEntity()
+ .getBackFacing()) {
+ return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(TAE.GTPP_INDEX(24)),
+ mIsOutputtingPower ? Textures.BlockIcons.OVERLAYS_ENERGY_OUT_MULTI[(int) this.getOutputTier()]
+ : Textures.BlockIcons.OVERLAYS_ENERGY_IN_MULTI[(int) this.getInputTier()] };
+ }
+ return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(TAE.GTPP_INDEX(23)) };
+ }
+
+ @Override
+ public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) {
+ // if (mBatteryCapacity <= 0) return false;
+ GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer);
+ return true;
+ }
+
+ private void checkMachineProblem(String msg, int xOff, int yOff, int zOff) {
+ final IGregTechTileEntity te = this.getBaseMetaTileEntity();
+ final Block tBlock = te.getBlockOffset(xOff, yOff, zOff);
+ final byte tMeta = te.getMetaIDOffset(xOff, yOff, zOff);
+ String name = tBlock.getLocalizedName();
+ String problem = msg + ": (" + xOff + ", " + yOff + ", " + zOff + ") " + name + ":" + tMeta;
+ checkMachineProblem(problem);
+ }
+
+ private void checkMachineProblem(String msg) {
+ if (!AsmConfig.disableAllLogging) {
+ Logger.INFO("Power Sub-Station problem: " + msg);
+ }
+ }
+
+ public static int getCellTier(Block aBlock, int aMeta) {
+ if (aBlock == ModBlocks.blockCasings2Misc && aMeta == 7) {
+ return 4;
+ } else if (aBlock == ModBlocks.blockCasings3Misc && aMeta == 4) {
+ return 5;
+ } else if (aBlock == ModBlocks.blockCasings3Misc && aMeta == 5) {
+ return 6;
+ } else if (aBlock == ModBlocks.blockCasings3Misc && aMeta == 6) {
+ return 7;
+ } else if (aBlock == ModBlocks.blockCasings3Misc && aMeta == 7) {
+ return 8;
+ } else if (aBlock == ModBlocks.blockCasings3Misc && aMeta == 8) {
+ return 9;
+ } else {
+ return -1;
+ }
+ }
+
+ public static int getMetaFromTier(int tier) {
+ if (tier == 4) return 7;
+ if (tier >= 5 && tier <= 9) return tier - 1;
+ return 0;
+ }
+
+ public static Block getBlockFromTier(int tier) {
+ return switch (tier) {
+ case 4 -> ModBlocks.blockCasings2Misc;
+ case 5, 6, 7, 8, 9 -> ModBlocks.blockCasings3Misc;
+ default -> null;
+ };
+ }
+
+ public static int getMaxHatchTier(int aCellTier) {
+ switch (aCellTier) {
+ case 9 -> {
+ return GT_Values.VOLTAGE_NAMES[9].equals("Ultimate High Voltage") ? 15 : 9;
+ }
+ default -> {
+ if (aCellTier < 4) {
+ return 0;
+ } else {
+ return aCellTier;
+ }
+ }
+ }
+ }
+
+ public static final int CELL_HEIGHT_MAX = 16;
+ public static final int CELL_HEIGHT_MIN = 2;
+
+ @Override
+ public IStructureDefinition<GregtechMetaTileEntity_PowerSubStationController> getStructureDefinition() {
+ if (STRUCTURE_DEFINITION == null) {
+ STRUCTURE_DEFINITION = StructureDefinition.<GregtechMetaTileEntity_PowerSubStationController>builder()
+ .addShape(
+ mName + "bottom",
+ transpose(new String[][] { { "BB~BB", "BBBBB", "BBBBB", "BBBBB", "BBBBB" } }))
+ .addShape(
+ mName + "layer",
+ transpose(new String[][] { { "CCCCC", "CIIIC", "CIIIC", "CIIIC", "CCCCC" } }))
+ .addShape(mName + "mid", transpose(new String[][] { { "CCCCC", "CHHHC", "CHHHC", "CHHHC", "CCCCC" } }))
+ .addShape(mName + "top", transpose(new String[][] { { "TTTTT", "TTTTT", "TTTTT", "TTTTT", "TTTTT" } }))
+ .addElement(
+ 'C',
+ buildHatchAdder(GregtechMetaTileEntity_PowerSubStationController.class)
+ .atLeast(Energy.or(TTEnergy), Dynamo.or(TTDynamo), Maintenance)
+ .disallowOnly(ForgeDirection.UP, ForgeDirection.DOWN)
+ .casingIndex(TAE.GTPP_INDEX(24))
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings2Misc, 8))))
+ .addElement(
+ 'B',
+ buildHatchAdder(GregtechMetaTileEntity_PowerSubStationController.class)
+ .atLeast(Energy.or(TTEnergy), Dynamo.or(TTDynamo), Maintenance)
+ .disallowOnly(ForgeDirection.UP)
+ .casingIndex(TAE.GTPP_INDEX(24))
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings2Misc, 8))))
+ .addElement(
+ 'T',
+ buildHatchAdder(GregtechMetaTileEntity_PowerSubStationController.class)
+ .atLeast(Energy.or(TTEnergy), Dynamo.or(TTDynamo), Maintenance)
+ .disallowOnly(ForgeDirection.DOWN)
+ .casingIndex(TAE.GTPP_INDEX(24))
+ .dot(1)
+ .buildAndChain(onElementPass(x -> ++x.mCasing, ofBlock(ModBlocks.blockCasings2Misc, 8))))
+ .addElement(
+ 'I',
+ withChannel(
+ "cell",
+ ofChain(
+ onlyIf(
+ x -> x.topState != TopState.NotTop,
+ onElementPass(
+ x -> x.topState = TopState.Top,
+ ofHatchAdderOptional(
+ GregtechMetaTileEntity_PowerSubStationController::addPowerSubStationList,
+ TAE.GTPP_INDEX(24),
+ 1,
+ ModBlocks.blockCasings2Misc,
+ 8))),
+ onlyIf(
+ x -> x.topState != TopState.Top,
+ onElementPass(
+ x -> x.topState = TopState.NotTop,
+ ofChain(
+ onElementPass(x -> ++x.cellCount[0], ofCell(4)),
+ onElementPass(x -> ++x.cellCount[1], ofCell(5)),
+ onElementPass(x -> ++x.cellCount[2], ofCell(6)),
+ onElementPass(x -> ++x.cellCount[3], ofCell(7)),
+ onElementPass(x -> ++x.cellCount[4], ofCell(8)),
+ onElementPass(x -> ++x.cellCount[5], ofCell(9))))))))
+ .addElement('H', ofCell(4))
+ .build();
+ }
+ return STRUCTURE_DEFINITION;
+ }
+
+ public static <T> IStructureElement<T> ofCell(int aIndex) {
+ return new IStructureElement<T>() {
+
+ @Override
+ public boolean check(T t, World world, int x, int y, int z) {
+ Block block = world.getBlock(x, y, z);
+ int meta = world.getBlockMetadata(x, y, z);
+ int tier = getCellTier(block, meta);
+ return aIndex == tier;
+ }
+
+ public int getIndex(int size) {
+ if (size > 6) size = 6;
+ return size + 3;
+ }
+
+ @Override
+ public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
+ StructureLibAPI.hintParticle(
+ world,
+ x,
+ y,
+ z,
+ getBlockFromTier(getIndex(trigger.stackSize)),
+ getMetaFromTier(getIndex(trigger.stackSize)));
+ return true;
+ }
+
+ @Override
+ public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
+ return world.setBlock(
+ x,
+ y,
+ z,
+ getBlockFromTier(getIndex(trigger.stackSize)),
+ getMetaFromTier(getIndex(trigger.stackSize)),
+ 3);
+ }
+
+ @Nullable
+ @Override
+ public BlocksToPlace getBlocksToPlace(T t, World world, int x, int y, int z, ItemStack trigger,
+ AutoPlaceEnvironment env) {
+ return BlocksToPlace.create(getBlockFromTier(trigger.stackSize), getMetaFromTier(trigger.stackSize));
+ }
+
+ @Override
+ public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger,
+ AutoPlaceEnvironment env) {
+ Block block = world.getBlock(x, y, z);
+ int meta = world.getBlockMetadata(x, y, z);
+ int tier = getCellTier(block, meta);
+ if (tier >= 0) return PlaceResult.SKIP;
+ return StructureUtility.survivalPlaceBlock(
+ getBlockFromTier(getIndex(trigger.stackSize)),
+ getMetaFromTier(getIndex(trigger.stackSize)),
+ world,
+ x,
+ y,
+ z,
+ env.getSource(),
+ env.getActor(),
+ env.getChatter());
+ }
+ };
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ int layer = Math.min(stackSize.stackSize + 3, 18);
+ log("Layer: " + layer);
+ log("Building 0");
+ buildPiece(mName + "bottom", stackSize, hintsOnly, 2, 0, 0);
+ log("Built 0");
+ for (int i = 1; i < layer - 1; i++) {
+ log("Building " + i);
+ buildPiece(mName + "mid", stackSize, hintsOnly, 2, i, 0);
+ log("Built " + i);
+ }
+ log("Building " + (layer - 1));
+ buildPiece(mName + "top", stackSize, hintsOnly, 2, layer - 1, 0);
+ log("Built " + (layer - 1));
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ int layer = Math.min(ChannelDataAccessor.getChannelData(stackSize, "height") + 3, 18);
+ int built;
+ built = survivialBuildPiece(mName + "bottom", stackSize, 2, 0, 0, elementBudget, env, false, true);
+ if (built >= 0) return built;
+ for (int i = 1; i < layer - 1; i++) {
+ built = survivialBuildPiece(mName + "mid", stackSize, 2, i, 0, elementBudget, env, false, true);
+ if (built >= 0) return built;
+ }
+ return survivialBuildPiece(mName + "top", stackSize, 2, layer - 1, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ mCasing = 0;
+ mEnergyHatches.clear();
+ mDynamoHatches.clear();
+ mTecTechEnergyHatches.clear();
+ mTecTechDynamoHatches.clear();
+ mAllEnergyHatches.clear();
+ mAllDynamoHatches.clear();
+ for (int i = 0; i < 6; i++) {
+ cellCount[i] = 0;
+ }
+ log("Checking 0");
+ if (!checkPiece(mName + "bottom", 2, 0, 0)) {
+ log("Failed on Layer 0");
+ return false;
+ }
+ log("Pass 0");
+ int layer = 1;
+ topState = TopState.MayBeTop;
+ while (true) {
+ if (!checkPiece(mName + "layer", 2, layer, 0)) return false;
+ layer++;
+ if (topState == TopState.Top) break; // top found, break out
+ topState = TopState.MayBeTop;
+ if (layer > 18) return false; // too many layers
+ }
+ int level = 0;
+ for (int i = 0; i < 6; i++) {
+ if (cellCount[i] != 0) {
+ if (level == 0) {
+ level = i + 4;
+ } else {
+ return false;
+ }
+ }
+ }
+ int tier = getMaxHatchTier(level);
+ long volSum = 0;
+ for (GT_MetaTileEntity_Hatch hatch : mAllDynamoHatches) {
+ if (hatch.mTier > tier || hatch.mTier < 3) {
+ return false;
+ }
+ volSum += (8L << (hatch.mTier * 2));
+ }
+ for (GT_MetaTileEntity_Hatch hatch : mAllEnergyHatches) {
+ if (hatch.mTier > tier || hatch.mTier < 3) {
+ return false;
+ }
+ volSum += (8L << (hatch.mTier * 2));
+ }
+ mBatteryCapacity = getCapacityFromCellTier(level) * cellCount[level - 4];
+ if (mAllEnergyHatches.size() + mAllDynamoHatches.size() > 0) {
+ mAverageEuUsage = volSum / (mAllEnergyHatches.size() + mAllDynamoHatches.size());
+ } else mAverageEuUsage = 0;
+ fixAllMaintenanceIssue();
+ return true;
+ }
+
+ public final boolean addPowerSubStationList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) {
+ if (aTileEntity == null) {
+ return false;
+ } else {
+ IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+ if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Energy) {
+ return addToMachineList(aTileEntity, aBaseCasingIndex);
+ } else if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Dynamo) {
+ return addToMachineList(aTileEntity, aBaseCasingIndex);
+ } else if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Maintenance) {
+ return addToMachineList(aTileEntity, aBaseCasingIndex);
+ } else if (TecTech.isModLoaded()) {
+ if (isThisHatchMultiDynamo(aMetaTileEntity)) {
+ return addToMachineList(aTileEntity, aBaseCasingIndex);
+ } else if (isThisHatchMultiEnergy(aMetaTileEntity)) {
+ return addToMachineList(aTileEntity, aBaseCasingIndex);
+ }
+ }
+ }
+ return false;
+ }
+
+ // Define storage capacity of smallest cell tier (EV) and compute higher tiers from it
+ private static final long CELL_TIER_EV_CAPACITY = 100 * 1000 * 1000;
+ private static final long CELL_TIER_MULTIPLIER = 4; // each tier's capacity is this many times the previous tier
+
+ public static long getCapacityFromCellTier(int aOverallCellTier) {
+ // Use integer math instead of `Math.pow` to avoid range/precision errors
+ if (aOverallCellTier < 4) return 0;
+ aOverallCellTier -= 4;
+ long capacity = CELL_TIER_EV_CAPACITY;
+ while (aOverallCellTier > 0) {
+ capacity *= CELL_TIER_MULTIPLIER;
+ aOverallCellTier--;
+ }
+ return capacity;
+ }
+
+ @Override
+ public int getMaxEfficiency(final ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(final ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(final IGregTechTileEntity aTileEntity) {
+ return new GregtechMetaTileEntity_PowerSubStationController(this.mName);
+ }
+
+ // mTotalEnergyAdded
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ aNBT.setLong("mAverageEuUsage", this.mAverageEuUsage);
+ this.mAverageEuAdded.write(aNBT, "mAverageEuAdded");
+ this.mAverageEuConsumed.write(aNBT, "mAverageEuConsumed");
+
+ // Usage Stats
+ aNBT.setLong("mTotalEnergyAdded", this.mTotalEnergyAdded);
+ aNBT.setLong("mTotalEnergyLost", this.mTotalEnergyLost);
+ aNBT.setLong("mTotalEnergyConsumed", this.mTotalEnergyConsumed);
+ aNBT.setLong("mTotalRunTime", this.mTotalRunTime);
+ aNBT.setBoolean("mIsOutputtingPower", this.mIsOutputtingPower);
+ aNBT.setLong("mBatteryCapacity", this.mBatteryCapacity);
+ super.saveNBTData(aNBT);
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+
+ // Best not to get a long if the Tag Map is holding an int
+ if (aNBT.hasKey("mAverageEuUsage")) {
+ this.mAverageEuUsage = aNBT.getLong("mAverageEuUsage");
+ }
+ switch (aNBT.func_150299_b("mAverageEuAdded")) {
+ case NBT.TAG_BYTE_ARRAY -> this.mAverageEuAdded.read(aNBT, "mAverageEuAdded");
+ case NBT.TAG_LONG -> this.mAverageEuAdded.set(aNBT.getLong("mAverageEuAdded"));
+ }
+ switch (aNBT.func_150299_b("mAverageEuConsumed")) {
+ case NBT.TAG_BYTE_ARRAY -> this.mAverageEuConsumed.read(aNBT, "mAverageEuConsumed");
+ case NBT.TAG_LONG -> this.mAverageEuConsumed.set(aNBT.getLong("mAverageEuConsumed"));
+ }
+
+ // Usage Stats
+ this.mTotalEnergyAdded = aNBT.getLong("mTotalEnergyAdded");
+ this.mTotalEnergyLost = aNBT.getLong("mTotalEnergyLost");
+ this.mTotalEnergyConsumed = aNBT.getLong("mTotalEnergyConsumed");
+ this.mTotalRunTime = aNBT.getLong("mTotalRunTime");
+
+ this.mIsOutputtingPower = aNBT.getBoolean("mIsOutputtingPower");
+
+ this.mBatteryCapacity = aNBT.getLong("mBatteryCapacity");
+
+ super.loadNBTData(aNBT);
+ }
+
+ @Override
+ public @NotNull CheckRecipeResult checkProcessing() {
+ this.mProgresstime = 0;
+ this.mMaxProgresstime = 200;
+ this.lEUt = 0;
+ this.mEfficiencyIncrease = 10000;
+ this.fixAllMaintenanceIssue();
+ return SimpleCheckRecipeResult.ofSuccess("managing_power");
+ }
+
+ @Override
+ public int getMaxParallelRecipes() {
+ return 1;
+ }
+
+ private long drawEnergyFromHatch(MetaTileEntity aHatch) {
+ long stored = aHatch.getEUVar();
+ long voltage = aHatch.maxEUInput() * aHatch.maxAmperesIn();
+
+ if (voltage > stored || (voltage + this.getEUVar() > this.mBatteryCapacity)) {
+ return 0;
+ }
+
+ if (this.getBaseMetaTileEntity()
+ .increaseStoredEnergyUnits(voltage, false)) {
+ aHatch.setEUVar((stored - voltage));
+ this.mTotalEnergyAdded += voltage;
+ return voltage;
+ }
+ return 0;
+ }
+
+ private long addEnergyToHatch(MetaTileEntity aHatch) {
+ long voltage = aHatch.maxEUOutput() * aHatch.maxAmperesOut();
+
+ if (aHatch.getEUVar() > aHatch.maxEUStore() - voltage) {
+ return 0;
+ }
+
+ if (this.getBaseMetaTileEntity()
+ .decreaseStoredEnergyUnits(voltage, false)) {
+ aHatch.getBaseMetaTileEntity()
+ .increaseStoredEnergyUnits(voltage, false);
+ this.mTotalEnergyConsumed += voltage;
+ return voltage;
+ }
+ return 0;
+ }
+
+ private long computeEnergyTax() {
+ float mTax = mAverageEuUsage * (ENERGY_TAX / 100f);
+
+ // Increase tax up to 2x if machine is not fully repaired (does not actually work at the moment, mEfficiency is
+ // always 0)
+ // mTax = mTax * (1f + (10000f - mEfficiency) / 10000f);
+
+ return MathUtils.roundToClosestLong(mTax);
+ }
+
+ @Override
+ public void onPreTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {
+ this.fixAllMaintenanceIssue();
+ }
+
+ @Override
+ public boolean onRunningTick(ItemStack aStack) {
+ // First, decay overcharge (1% of stored energy plus 1000 EU per tick)
+ if (this.getEUVar() > this.mBatteryCapacity) {
+ long energy = (long) (this.getEUVar() * 0.990f) - 1000;
+ this.setEUVar(energy);
+ }
+
+ // Pay Tax
+ long mDecrease = computeEnergyTax();
+ this.mTotalEnergyLost += Math.min(mDecrease, this.getEUVar());
+ this.setEUVar(Math.max(0, this.getEUVar() - mDecrease));
+
+ long aInputAverage = 0;
+ long aOutputAverage = 0;
+ // Input Power
+ for (GT_MetaTileEntity_Hatch THatch : filterValidMTEs(this.mDischargeHatches)) {
+ aInputAverage += drawEnergyFromHatch(THatch);
+ }
+ for (GT_MetaTileEntity_Hatch tHatch : filterValidMTEs(this.mAllEnergyHatches)) {
+ aInputAverage += drawEnergyFromHatch(tHatch);
+ }
+
+ // Output Power
+ for (GT_MetaTileEntity_Hatch THatch : filterValidMTEs(this.mChargeHatches)) {
+ aOutputAverage += addEnergyToHatch(THatch);
+ }
+ for (GT_MetaTileEntity_Hatch tHatch : filterValidMTEs(this.mAllDynamoHatches)) {
+ aOutputAverage += addEnergyToHatch(tHatch);
+ }
+ // reset progress time
+ mProgresstime = 0;
+
+ this.mAverageEuAdded.sample(aInputAverage);
+ this.mAverageEuConsumed.sample(aOutputAverage);
+
+ return true;
+ }
+
+ @Override
+ public boolean drainEnergyInput(long aEU) {
+ // Not applicable to this machine
+ return true;
+ }
+
+ @Override
+ public boolean addEnergyOutput(long aEU) {
+ // Not applicable to this machine
+ return true;
+ }
+
+ @Override
+ public long maxEUStore() {
+ return mBatteryCapacity;
+ }
+
+ @Override
+ public long getMinimumStoredEU() {
+ return 0;
+ }
+
+ @Override
+ public String[] getExtraInfoData() {
+ String mode;
+ if (mIsOutputtingPower) {
+ mode = EnumChatFormatting.GOLD + "Output" + EnumChatFormatting.RESET;
+ } else {
+ mode = EnumChatFormatting.BLUE + "Input" + EnumChatFormatting.RESET;
+ }
+
+ String storedEnergyText;
+ if (this.getEUVar() > this.mBatteryCapacity) {
+ storedEnergyText = EnumChatFormatting.RED + GT_Utility.formatNumbers(this.getEUVar())
+ + EnumChatFormatting.RESET;
+ } else {
+ storedEnergyText = EnumChatFormatting.GREEN + GT_Utility.formatNumbers(this.getEUVar())
+ + EnumChatFormatting.RESET;
+ }
+
+ int errorCode = this.getBaseMetaTileEntity()
+ .getErrorDisplayID();
+ boolean mMaint = (errorCode != 0);
+
+ return new String[] { "Ergon Energy - District Sub-Station", "Stored EU: " + storedEnergyText,
+ "Capacity: " + EnumChatFormatting.YELLOW
+ + GT_Utility.formatNumbers(this.maxEUStore())
+ + EnumChatFormatting.RESET,
+ "Running Costs: " + EnumChatFormatting.RED
+ + GT_Utility.formatNumbers(this.computeEnergyTax())
+ + EnumChatFormatting.RESET
+ + " EU/t",
+ "Controller Mode: " + mode,
+ "Requires Maintenance: " + (!mMaint ? EnumChatFormatting.GREEN : EnumChatFormatting.RED)
+ + mMaint
+ + EnumChatFormatting.RESET
+ + " | Code: ["
+ + (!mMaint ? EnumChatFormatting.GREEN : EnumChatFormatting.RED)
+ + errorCode
+ + EnumChatFormatting.RESET
+ + "]",
+ "----------------------", "Stats for Nerds",
+ "Average Input: " + EnumChatFormatting.BLUE
+ + GT_Utility.formatNumbers(this.getAverageEuAdded())
+ + EnumChatFormatting.RESET
+ + " EU",
+ "Average Output: " + EnumChatFormatting.GOLD
+ + GT_Utility.formatNumbers(this.getAverageEuConsumed())
+ + EnumChatFormatting.RESET
+ + " EU",
+ "Total Input: " + EnumChatFormatting.BLUE
+ + GT_Utility.formatNumbers(this.mTotalEnergyAdded)
+ + EnumChatFormatting.RESET
+ + " EU",
+ "Total Output: " + EnumChatFormatting.GOLD
+ + GT_Utility.formatNumbers(this.mTotalEnergyConsumed)
+ + EnumChatFormatting.RESET
+ + " EU",
+ "Total Costs: " + EnumChatFormatting.RED
+ + GT_Utility.formatNumbers(this.mTotalEnergyLost)
+ + EnumChatFormatting.RESET
+ + " EU", };
+ }
+
+ @Override
+ public void explodeMultiblock() {
+ // TODO Auto-generated method stub
+ super.explodeMultiblock();
+ }
+
+ @Override
+ public void doExplosion(long aExplosionPower) {
+ // TODO Auto-generated method stub
+ super.doExplosion(aExplosionPower);
+ }
+
+ @Override
+ public long getMaxInputVoltage() {
+ return 32768;
+ }
+
+ @Override
+ public boolean isElectric() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnetInput() {
+ return !mIsOutputtingPower;
+ }
+
+ @Override
+ public boolean isEnetOutput() {
+ return mIsOutputtingPower;
+ }
+
+ @Override
+ public boolean isInputFacing(ForgeDirection side) {
+ return (side == this.getBaseMetaTileEntity()
+ .getBackFacing() && !mIsOutputtingPower);
+ }
+
+ @Override
+ public boolean isOutputFacing(ForgeDirection side) {
+ return (side == this.getBaseMetaTileEntity()
+ .getBackFacing() && mIsOutputtingPower);
+ }
+
+ @Override
+ public long maxAmperesIn() {
+ return 32;
+ }
+
+ @Override
+ public long maxAmperesOut() {
+ return 32;
+ }
+
+ @Override
+ public long maxEUInput() {
+ return 32768;
+ }
+
+ @Override
+ public long maxEUOutput() {
+ return 32768;
+ }
+
+ public final long getAverageEuAdded() {
+ return this.mAverageEuAdded.get();
+ }
+
+ public final long getAverageEuConsumed() {
+ return this.mAverageEuConsumed.get();
+ }
+
+ @Override
+ public void onModeChangeByScrewdriver(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
+ mIsOutputtingPower = !mIsOutputtingPower;
+ if (mIsOutputtingPower) {
+ PlayerUtils.messagePlayer(aPlayer, "Sub-Station is now outputting power from the controller.");
+ } else {
+ PlayerUtils.messagePlayer(aPlayer, "Sub-Station is now inputting power into the controller.");
+ }
+ }
+
+ @Override
+ public boolean doesBindPlayerInventory() {
+ return false;
+ }
+
+ @Override
+ public int getGUIWidth() {
+ return 196;
+ }
+
+ @Override
+ public int getGUIHeight() {
+ return 191;
+ }
+
+ @Override
+ public void addGregTechLogo(ModularWindow.Builder builder) {
+ builder.widget(
+ new DrawableWidget().setDrawable(getGUITextureSet().getGregTechLogo())
+ .setSize(17, 17)
+ .setPos(175, 166));
+ }
+
+ private long clientEUIn, clientEUOut, clientEULoss, clientEUStored;
+ private float clientProgress;
+
+ protected static final NumberFormatMUI numberFormat = new NumberFormatMUI();
+
+ @Override
+ public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) {
+ builder.widget(
+ new DrawableWidget().setDrawable(GT_UITextures.PICTURE_SCREEN_BLACK)
+ .setPos(4, 4)
+ .setSize(149, 149))
+ .widget(new SlotWidget(inventoryHandler, 0).setPos(154, 4))
+ .widget(
+ new SlotWidget(inventoryHandler, 1).setAccess(true, false)
+ .setPos(154, 22))
+ .widget(
+ SlotGroup.ofItemHandler(new PlayerMainInvWrapper(buildContext.getPlayer().inventory), 9)
+ .endAtSlot(8)
+ .build()
+ .setPos(7, 166))
+ .widget(
+ TextWidget
+ .dynamicString(
+ () -> getBaseMetaTileEntity().getErrorDisplayID() == 0
+ ? getBaseMetaTileEntity().isActive() ? "Running perfectly" : "Turn on with Mallet"
+ : "")
+ .setSynced(false)
+ .setDefaultColor(COLOR_TEXT_WHITE.get())
+ .setPos(10, 8))
+ .widget(
+ new FakeSyncWidget.BooleanSyncer(
+ () -> getBaseMetaTileEntity().isActive(),
+ val -> getBaseMetaTileEntity().setActive(val)))
+ .widget(
+ new FakeSyncWidget.IntegerSyncer(
+ () -> getBaseMetaTileEntity().getErrorDisplayID(),
+ val -> getBaseMetaTileEntity().setErrorDisplayID(val)))
+ .widget(
+ new TextWidget("In").setDefaultColor(COLOR_TEXT_WHITE.get())
+ .setPos(178, 10))
+ .widget(
+ new TextWidget("Out").setDefaultColor(COLOR_TEXT_WHITE.get())
+ .setPos(176, 28))
+ .widget(new FakeSyncWidget.LongSyncer(this::getAverageEuAdded, val -> clientEUIn = val))
+ .widget(
+ new TextWidget().setStringSupplier(() -> "Avg In: " + numberFormat.format(clientEUIn) + " EU")
+ .setDefaultColor(COLOR_TEXT_WHITE.get())
+ .setPos(10, 20))
+ .widget(new FakeSyncWidget.LongSyncer(this::getAverageEuConsumed, val -> clientEUOut = val))
+ .widget(
+ new TextWidget().setStringSupplier(() -> "Avg Out: " + numberFormat.format(clientEUOut) + " EU")
+ .setDefaultColor(COLOR_TEXT_WHITE.get())
+ .setPos(10, 30))
+ .widget(new FakeSyncWidget.LongSyncer(this::computeEnergyTax, val -> clientEULoss = val))
+ .widget(
+ new TextWidget()
+ .setStringSupplier(() -> "Powerloss: " + numberFormat.format(clientEULoss) + " EU per tick")
+ .setDefaultColor(COLOR_TEXT_WHITE.get())
+ .setPos(10, 40))
+ .widget(
+ new DrawableWidget().setDrawable(GTPP_UITextures.PICTURE_ENERGY_FRAME)
+ .setPos(4, 155)
+ .setSize(149, 7))
+ .widget(new FakeSyncWidget.FloatSyncer(this::getProgress, val -> clientProgress = val))
+ .widget(
+ new ProgressBar().setProgress(this::getProgress)
+ .setTexture(GTPP_UITextures.PROGRESSBAR_PSS_ENERGY, 147)
+ .setDirection(ProgressBar.Direction.RIGHT)
+ .setPos(5, 156)
+ .setSize(147, 5))
+ .widget(
+ new TextWidget("Stored:").setDefaultColor(COLOR_TEXT_WHITE.get())
+ .setPos(10, 132))
+ .widget(
+ new FakeSyncWidget.LongSyncer(() -> getBaseMetaTileEntity().getStoredEU(), val -> clientEUStored = val))
+ .widget(new TextWidget().setTextSupplier(() -> {
+ int colorScale = (int) (clientProgress * 100 * 2.55);
+ return new Text(numberFormat.format(clientEUStored) + " EU")
+ .color(Utils.rgbtoHexValue((255 - colorScale), colorScale, 0));
+ })
+ .setPos(10, 142))
+ .widget(
+ new TextWidget().setStringSupplier(() -> numberFormat.format(clientProgress * 100) + "%")
+ .setDefaultColor(COLOR_TEXT_WHITE.get())
+ .setPos(70, 155));
+ }
+
+ private float getProgress() {
+ return (float) getBaseMetaTileEntity().getStoredEU() / getBaseMetaTileEntity().getEUCapacity();
+ }
+}