diff options
author | Raven Szewczyk <git@eigenraven.me> | 2024-05-24 19:50:35 +0100 |
---|---|---|
committer | Raven Szewczyk <git@eigenraven.me> | 2024-05-24 19:50:35 +0100 |
commit | 6d1b2216464d4dad449ac6fcfec476832224a55e (patch) | |
tree | 526a0c15f7056313c80e6c0386e025e9b3f61781 /src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines | |
parent | b5d35f40afa606ed1b07061dad82e0521a59c186 (diff) | |
download | GT5-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')
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(); + } +} |