From 2b5d23fbc1aad424763d06d42c6d61745eee5012 Mon Sep 17 00:00:00 2001 From: Boblet Date: Tue, 18 Nov 2025 15:20:28 +0100 Subject: [PATCH] blibble futuristics' greatest invention: the fugorg mechanism --- changelog | 1 + .../machine/fusion/MachineFusionBreeder.java | 19 +++- .../fusion/MachineFusionCollector.java | 2 - .../hbm/inventory/gui/GUIFusionKlystron.java | 5 +- .../com/hbm/inventory/gui/GUIFusionTorus.java | 6 +- .../hbm/inventory/recipes/FusionRecipe.java | 4 + .../hbm/inventory/recipes/FusionRecipes.java | 89 +++++++++++++++++- .../recipes/loader/GenericRecipes.java | 2 +- .../machine/TileEntityFoundryChannel.java | 2 +- .../machine/fusion/IFusionPowerReceiver.java | 10 ++ .../fusion/TileEntityFusionBreeder.java | 75 ++++++++++++++- .../fusion/TileEntityFusionKlystron.java | 2 +- .../machine/fusion/TileEntityFusionTorus.java | 31 +++++- src/main/java/com/hbm/uninos/GenNode.java | 2 + .../com/hbm/world/gen/NTMWorldGenerator.java | 86 ++++++++--------- src/main/resources/assets/hbm/lang/en_US.lang | 1 + .../gui/reactors/gui_fusion_breeder.png | Bin 0 -> 3055 bytes .../gui/reactors/gui_fusion_klystron.png | Bin 3386 -> 3378 bytes .../gui/reactors/gui_fusion_torus.png | Bin 4927 -> 4931 bytes 19 files changed, 277 insertions(+), 60 deletions(-) create mode 100644 src/main/java/com/hbm/tileentity/machine/fusion/IFusionPowerReceiver.java create mode 100644 src/main/resources/assets/hbm/textures/gui/reactors/gui_fusion_breeder.png diff --git a/changelog b/changelog index b6193771d..3c93a2fc6 100644 --- a/changelog +++ b/changelog @@ -64,3 +64,4 @@ * Fixed light blue and light gray dyes not working when dyeing cables * Fixed bismuth armor not having a valid repair material * Fixed compressors needing at least one mB of fluid more to process a recipe than necessary +* Fixed many NTM structure spawn conditions being hardcoded (again) preventing them from spawning in modded biomes that would otherwise be a fit diff --git a/src/main/java/com/hbm/blocks/machine/fusion/MachineFusionBreeder.java b/src/main/java/com/hbm/blocks/machine/fusion/MachineFusionBreeder.java index af9421e30..ede4e3fe1 100644 --- a/src/main/java/com/hbm/blocks/machine/fusion/MachineFusionBreeder.java +++ b/src/main/java/com/hbm/blocks/machine/fusion/MachineFusionBreeder.java @@ -5,6 +5,7 @@ import com.hbm.tileentity.TileEntityProxyCombo; import com.hbm.tileentity.machine.fusion.TileEntityFusionBreeder; import net.minecraft.block.material.Material; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; @@ -18,7 +19,7 @@ public class MachineFusionBreeder extends BlockDummyable { @Override public TileEntity createNewTileEntity(World world, int meta) { if(meta >= 12) return new TileEntityFusionBreeder(); - if(meta >= 6) return new TileEntityProxyCombo().power().fluid(); + if(meta >= 6) return new TileEntityProxyCombo().inventory().fluid(); return null; } @@ -31,6 +32,11 @@ public class MachineFusionBreeder extends BlockDummyable { public int getOffset() { return 2; } + + @Override + public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float hitX, float hitY, float hitZ) { + return super.standardOpenBehavior(world, x, y, z, player, 0); + } @Override public boolean checkRequirement(World world, int x, int y, int z, ForgeDirection dir, int o) { @@ -40,5 +46,16 @@ public class MachineFusionBreeder extends BlockDummyable { @Override public void fillSpace(World world, int x, int y, int z, ForgeDirection dir, int o) { super.fillSpace(world, x, y, z, dir, o); + + x += dir.offsetX * o; + z += dir.offsetZ * o; + + ForgeDirection rot = dir.getRotation(ForgeDirection.UP); + + this.makeExtra(world, x + rot.offsetX, y, z + rot.offsetZ); + this.makeExtra(world, x - rot.offsetX, y, z - rot.offsetZ); + this.makeExtra(world, x + dir.offsetX + rot.offsetX, y, z + dir.offsetZ + rot.offsetZ); + this.makeExtra(world, x + dir.offsetX - rot.offsetX, y, z + dir.offsetZ - rot.offsetZ); + this.makeExtra(world, x + dir.offsetX * 2, y + 2, z + dir.offsetZ * 2); } } diff --git a/src/main/java/com/hbm/blocks/machine/fusion/MachineFusionCollector.java b/src/main/java/com/hbm/blocks/machine/fusion/MachineFusionCollector.java index 8a78f43b5..39383ceb4 100644 --- a/src/main/java/com/hbm/blocks/machine/fusion/MachineFusionCollector.java +++ b/src/main/java/com/hbm/blocks/machine/fusion/MachineFusionCollector.java @@ -1,7 +1,6 @@ package com.hbm.blocks.machine.fusion; import com.hbm.blocks.BlockDummyable; -import com.hbm.tileentity.TileEntityProxyCombo; import com.hbm.tileentity.machine.fusion.TileEntityFusionCollector; import net.minecraft.block.material.Material; @@ -18,7 +17,6 @@ public class MachineFusionCollector extends BlockDummyable { @Override public TileEntity createNewTileEntity(World world, int meta) { if(meta >= 12) return new TileEntityFusionCollector(); - if(meta >= 6) return new TileEntityProxyCombo().power().fluid(); return null; } diff --git a/src/main/java/com/hbm/inventory/gui/GUIFusionKlystron.java b/src/main/java/com/hbm/inventory/gui/GUIFusionKlystron.java index 162167848..88915f579 100644 --- a/src/main/java/com/hbm/inventory/gui/GUIFusionKlystron.java +++ b/src/main/java/com/hbm/inventory/gui/GUIFusionKlystron.java @@ -17,6 +17,7 @@ import net.minecraft.client.gui.GuiTextField; import net.minecraft.client.resources.I18n; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.ResourceLocation; public class GUIFusionKlystron extends GuiInfoContainer { @@ -51,9 +52,9 @@ public class GUIFusionKlystron extends GuiInfoContainer { this.drawElectricityInfo(this, mouseX, mouseY, guiLeft + 8, guiTop + 18, 16, 52, klystron.power, klystron.getMaxPower()); - drawCustomInfoStat(mouseX, mouseY, guiLeft + 43, guiTop + 71, 18, 18, mouseX, mouseY, BobMathUtil.getShortNumber(klystron.output) + "KyU / " + BobMathUtil.getShortNumber(klystron.outputTarget) + "KyU"); + drawCustomInfoStat(mouseX, mouseY, guiLeft + 43, guiTop + 71, 18, 18, mouseX, mouseY, EnumChatFormatting.RED + "<- " + EnumChatFormatting.RESET + BobMathUtil.getShortNumber(klystron.output) + "KyU / " + BobMathUtil.getShortNumber(klystron.outputTarget) + "KyU"); klystron.compair.renderTankInfo(this, mouseX, mouseY, guiLeft + 76, guiTop + 71, 18, 18); - drawCustomInfoStat(mouseX, mouseY, guiLeft + 115, guiTop + 71, 18, 18, mouseX, mouseY, BobMathUtil.getShortNumber(klystron.output) + "HE / " + BobMathUtil.getShortNumber(klystron.outputTarget) + "HE"); + drawCustomInfoStat(mouseX, mouseY, guiLeft + 115, guiTop + 71, 18, 18, mouseX, mouseY, EnumChatFormatting.GREEN + "-> " + EnumChatFormatting.RESET + BobMathUtil.getShortNumber(klystron.output) + "HE / " + BobMathUtil.getShortNumber(klystron.outputTarget) + "HE"); } diff --git a/src/main/java/com/hbm/inventory/gui/GUIFusionTorus.java b/src/main/java/com/hbm/inventory/gui/GUIFusionTorus.java index 53334a99d..f682eb767 100644 --- a/src/main/java/com/hbm/inventory/gui/GUIFusionTorus.java +++ b/src/main/java/com/hbm/inventory/gui/GUIFusionTorus.java @@ -44,12 +44,12 @@ public class GUIFusionTorus extends GuiInfoContainer { FusionRecipe recipe = (FusionRecipe) FusionRecipes.INSTANCE.recipeNameMap.get(this.torus.fusionModule.recipe); if(recipe != null) { - drawCustomInfoStat(mouseX, mouseY, guiLeft + 43, guiTop + 115, 18, 18, mouseX, mouseY, BobMathUtil.getShortNumber(torus.klystronEnergy) + "KyU / " + BobMathUtil.getShortNumber(recipe.ignitionTemp) + "KyU"); - drawCustomInfoStat(mouseX, mouseY, guiLeft + 79, guiTop + 115, 18, 18, mouseX, mouseY, BobMathUtil.getShortNumber(torus.plasmaEnergy) + "TU / " + BobMathUtil.getShortNumber(recipe.outputTemp) + "TU"); + drawCustomInfoStat(mouseX, mouseY, guiLeft + 43, guiTop + 115, 18, 18, mouseX, mouseY, EnumChatFormatting.GREEN + "-> " + EnumChatFormatting.RESET + BobMathUtil.getShortNumber(torus.klystronEnergy) + "KyU / " + BobMathUtil.getShortNumber(recipe.ignitionTemp) + "KyU"); + drawCustomInfoStat(mouseX, mouseY, guiLeft + 79, guiTop + 115, 18, 18, mouseX, mouseY, EnumChatFormatting.RED + "<- " + EnumChatFormatting.RESET + BobMathUtil.getShortNumber(torus.plasmaEnergy) + "TU / " + BobMathUtil.getShortNumber(recipe.outputTemp) + "TU"); String[] lines = new String[recipe.inputFluid.length]; for(int i = 0; i < lines.length; i++) { int consumption = (int) Math.ceil(recipe.inputFluid[i].fill * torus.fuelConsumption); - lines[i] = consumption + "mB/t " + recipe.inputFluid[i].type.getLocalizedName(); + lines[i] = EnumChatFormatting.GREEN + "-> " + EnumChatFormatting.RESET + consumption + "mB/t " + recipe.inputFluid[i].type.getLocalizedName(); } drawCustomInfoStat(mouseX, mouseY, guiLeft + 115, guiTop + 115, 18, 18, mouseX, mouseY, lines); } else { diff --git a/src/main/java/com/hbm/inventory/recipes/FusionRecipe.java b/src/main/java/com/hbm/inventory/recipes/FusionRecipe.java index 5e6bb67ad..c85e07637 100644 --- a/src/main/java/com/hbm/inventory/recipes/FusionRecipe.java +++ b/src/main/java/com/hbm/inventory/recipes/FusionRecipe.java @@ -15,11 +15,14 @@ public class FusionRecipe extends GenericRecipe { public long ignitionTemp; // plasma output energy at full blast public long outputTemp; + // neutron output energy at full blast + public double neutronFlux; public FusionRecipe(String name) { super(name); } public FusionRecipe setInputEnergy(long ignitionTemp) { this.ignitionTemp = ignitionTemp; return this; } public FusionRecipe setOutputEnergy(long outputTemp) { this.outputTemp = outputTemp; return this; } + public FusionRecipe setOutputFlux(double neutronFlux) { this.neutronFlux = neutronFlux; return this; } public List print() { List list = new ArrayList(); @@ -29,6 +32,7 @@ public class FusionRecipe extends GenericRecipe { power(list); list.add(EnumChatFormatting.RED + I18nUtil.resolveKey("gui.recipe.fusionIn") + ": " + BobMathUtil.getShortNumber(ignitionTemp) + "KyU/t"); list.add(EnumChatFormatting.RED + I18nUtil.resolveKey("gui.recipe.fusionOut") + ": " + BobMathUtil.getShortNumber(outputTemp) + "TU/t"); + list.add(EnumChatFormatting.RED + I18nUtil.resolveKey("gui.recipe.fusionFlux") + ": " + ((int)(neutronFlux * 10)) / 10D + " flux/t"); input(list); output(list); diff --git a/src/main/java/com/hbm/inventory/recipes/FusionRecipes.java b/src/main/java/com/hbm/inventory/recipes/FusionRecipes.java index d91d3e431..2852d17b2 100644 --- a/src/main/java/com/hbm/inventory/recipes/FusionRecipes.java +++ b/src/main/java/com/hbm/inventory/recipes/FusionRecipes.java @@ -1,8 +1,17 @@ package com.hbm.inventory.recipes; +import java.io.IOException; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.stream.JsonWriter; import com.hbm.inventory.FluidStack; import com.hbm.inventory.fluid.Fluids; import com.hbm.inventory.recipes.loader.GenericRecipes; +import com.hbm.items.ModItems; +import com.hbm.tileentity.machine.fusion.TileEntityFusionBreeder; + +import net.minecraft.item.ItemStack; public class FusionRecipes extends GenericRecipes { @@ -19,11 +28,87 @@ public class FusionRecipes extends GenericRecipes { @Override public void registerDefaults() { - long solenoid = 100_000; + long solenoid = 25_000; + double breederCapacity = TileEntityFusionBreeder.capacity; - this.register((FusionRecipe) new FusionRecipe("fus.d-t").setInputEnergy(1_000_000).setOutputEnergy(20_000_000) + /// DEMO /// + + // mostly for breeding helium and tritium, energy gains are enough to ignite TH4 + // 15MHE/s to 20MHE/s + this.register((FusionRecipe) new FusionRecipe("fus.dd").setInputEnergy(750_000).setOutputEnergy(1_000_000).setOutputFlux(breederCapacity / 200) + .setPower(solenoid).setDuration(100) + .inputFluids(new FluidStack(Fluids.DEUTERIUM, 20)) + .outputFluids(new FluidStack(Fluids.HELIUM4, 1_000))); // akshuyally it should be helium-3 muh realisme + + // early fuel + // 5MHE/s to 20MHE/s + this.register((FusionRecipe) new FusionRecipe("fus.do").setInputEnergy(250_000).setOutputEnergy(1_250_000).setOutputFlux(breederCapacity / 200) + .setPower(solenoid).setDuration(100) + .inputFluids(new FluidStack(Fluids.DEUTERIUM, 10), new FluidStack(Fluids.OXYGEN, 10)) + .outputItems(new ItemStack(ModItems.pellet_charged))); + + // medium fuel + // 15MHE/s to 75MHE/s + this.register((FusionRecipe) new FusionRecipe("fus.dt").setInputEnergy(750_000).setOutputEnergy(3_750_000).setOutputFlux(breederCapacity / 100) .setPower(solenoid).setDuration(100) .inputFluids(new FluidStack(Fluids.DEUTERIUM, 10), new FluidStack(Fluids.TRITIUM, 10)) .outputFluids(new FluidStack(Fluids.HELIUM4, 1_000))); + + // medium fuel, three klystrons or in tandem + // 50MHE/s to 125MHE/s + this.register((FusionRecipe) new FusionRecipe("fus.tcl").setInputEnergy(2_500_000).setOutputEnergy(6_250_000).setOutputFlux(breederCapacity / 20) + .setPower(solenoid).setDuration(100) + .inputFluids(new FluidStack(Fluids.TRITIUM, 10), new FluidStack(Fluids.CHLORINE, 10)) + .outputItems(new ItemStack(ModItems.pellet_charged))); + + // medium fuel, aneutronic + // 10MHE/s to 75MHE/s + this.register((FusionRecipe) new FusionRecipe("fus.h3").setInputEnergy(500_000).setOutputEnergy(3_750_000).setOutputFlux(0) + .setPower(solenoid).setDuration(100) + .inputFluids(new FluidStack(Fluids.HELIUM3, 20)) + .outputFluids(new FluidStack(Fluids.HELIUM4, 1_000))); + + // medium fuel, in tandem with DD + // 17.5MHE/s to 80MHE/s + this.register((FusionRecipe) new FusionRecipe("fus.th4").setInputEnergy(875_000).setOutputEnergy(4_000_000).setOutputFlux(breederCapacity / 20) + .setPower(solenoid).setDuration(100) + .inputFluids(new FluidStack(Fluids.TRITIUM, 10), new FluidStack(Fluids.HELIUM4, 10)) + .outputItems(new ItemStack(ModItems.pellet_charged))); + + // high fuel, ignition exceeds klystron power, requires TH4 or H3 + // 75MHE/s to 200MHE/s + this.register((FusionRecipe) new FusionRecipe("fus.cl").setInputEnergy(3_750_000).setOutputEnergy(10_000_000).setOutputFlux(breederCapacity / 10) + .setPower(solenoid).setDuration(100) + .inputFluids(new FluidStack(Fluids.CHLORINE, 20)) + .outputItems(new ItemStack(ModItems.pellet_charged))); + + /// DEMO /// + + + /* + * TODO: + * chlorophyte and more liquid byproduct types + * stellar flux plasma (post ICF, erisite?) + * balefire plasma (raw balefire instead of rocket fuel?) + * scrap ionized particle liquefaction recipe + * deuterated carbon (deut + refgas + syngas in a chemplant) + */ + } + + // foresight! yeah! + @Override + public void readExtraData(JsonElement element, FusionRecipe recipe) { + JsonObject obj = (JsonObject) element; + + recipe.ignitionTemp = obj.get("ignitionTemp").getAsLong(); + recipe.outputTemp = obj.get("outputTemp").getAsLong(); + recipe.neutronFlux = obj.get("outputFlux").getAsDouble(); + } + + @Override + public void writeExtraData(FusionRecipe recipe, JsonWriter writer) throws IOException { + writer.name("ignitionTemp").value(recipe.ignitionTemp); + writer.name("outputTemp").value(recipe.outputTemp); + writer.name("outputFlux").value(recipe.neutronFlux); } } diff --git a/src/main/java/com/hbm/inventory/recipes/loader/GenericRecipes.java b/src/main/java/com/hbm/inventory/recipes/loader/GenericRecipes.java index 0bee0728a..27eb9c69f 100644 --- a/src/main/java/com/hbm/inventory/recipes/loader/GenericRecipes.java +++ b/src/main/java/com/hbm/inventory/recipes/loader/GenericRecipes.java @@ -173,7 +173,7 @@ public abstract class GenericRecipes extends Serializab writeExtraData(recipe, writer); } - public void writeExtraData(T recipe, JsonWriter writer) { } + public void writeExtraData(T recipe, JsonWriter writer) throws IOException { } public IOutput[] readOutputArray(JsonArray array) { IOutput[] output = new IOutput[array.size()]; diff --git a/src/main/java/com/hbm/tileentity/machine/TileEntityFoundryChannel.java b/src/main/java/com/hbm/tileentity/machine/TileEntityFoundryChannel.java index 0ffaffefe..2dec72155 100644 --- a/src/main/java/com/hbm/tileentity/machine/TileEntityFoundryChannel.java +++ b/src/main/java/com/hbm/tileentity/machine/TileEntityFoundryChannel.java @@ -179,7 +179,7 @@ public class TileEntityFoundryChannel extends TileEntityFoundryBase { @Override public boolean canAcceptPartialPour(World world, int x, int y, int z, double dX, double dY, double dZ, ForgeDirection side, MaterialStack stack) { - if(this.node == null) return false; + if(this.node == null || !this.node.hasValidNet()) return false; for(Object o : this.node.net.links) { FoundryNode node = (FoundryNode) o; if(node.type != null && node.type != stack.material) { diff --git a/src/main/java/com/hbm/tileentity/machine/fusion/IFusionPowerReceiver.java b/src/main/java/com/hbm/tileentity/machine/fusion/IFusionPowerReceiver.java new file mode 100644 index 000000000..f139a8bcb --- /dev/null +++ b/src/main/java/com/hbm/tileentity/machine/fusion/IFusionPowerReceiver.java @@ -0,0 +1,10 @@ +package com.hbm.tileentity.machine.fusion; + +public interface IFusionPowerReceiver { + + /** + * fusionPower is the per-port output adjusted for the amount of connected receivers (i.e. when boilers share output energy) + * neutronPower is a fixed value provided by the recipe + */ + public void receiveFusionPower(long fusionPower, double neutronPower); +} diff --git a/src/main/java/com/hbm/tileentity/machine/fusion/TileEntityFusionBreeder.java b/src/main/java/com/hbm/tileentity/machine/fusion/TileEntityFusionBreeder.java index 24d58bf62..96abb0088 100644 --- a/src/main/java/com/hbm/tileentity/machine/fusion/TileEntityFusionBreeder.java +++ b/src/main/java/com/hbm/tileentity/machine/fusion/TileEntityFusionBreeder.java @@ -1,26 +1,56 @@ package com.hbm.tileentity.machine.fusion; +import com.hbm.inventory.fluid.Fluids; +import com.hbm.inventory.fluid.tank.FluidTank; +import com.hbm.tileentity.IGUIProvider; +import com.hbm.tileentity.TileEntityMachineBase; import com.hbm.uninos.GenNode; import com.hbm.uninos.UniNodespace; import com.hbm.uninos.networkproviders.PlasmaNetworkProvider; import com.hbm.util.fauxpointtwelve.BlockPos; import com.hbm.util.fauxpointtwelve.DirPos; +import api.hbm.fluidmk2.IFluidStandardTransceiverMK2; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; -import net.minecraft.tileentity.TileEntity; +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; import net.minecraft.util.AxisAlignedBB; +import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; -public class TileEntityFusionBreeder extends TileEntity { +public class TileEntityFusionBreeder extends TileEntityMachineBase implements IFluidStandardTransceiverMK2, IGUIProvider { protected GenNode plasmaNode; + public FluidTank[] tanks; + + public static final double capacity = 10_000D; + + public TileEntityFusionBreeder() { + super(2); + + tanks = new FluidTank[2]; + tanks[0] = new FluidTank(Fluids.NONE, 16_000); + tanks[1] = new FluidTank(Fluids.NONE, 16_000); + } + + @Override + public String getName() { + return "container.fusionBreeder"; + } + @Override public void updateEntity() { if(!worldObj.isRemote) { + for(DirPos pos : getConPos()) { + if(tanks[0].getTankType() != Fluids.NONE) this.trySubscribe(tanks[0].getTankType(), worldObj, pos); + if(tanks[1].getFill() > 0) this.tryProvide(tanks[1], worldObj, pos); + } + if(plasmaNode == null || plasmaNode.expired) { ForgeDirection dir = ForgeDirection.getOrientation(this.getBlockMetadata() - 10).getOpposite(); plasmaNode = UniNodespace.getNode(worldObj, xCoord + dir.offsetX * 2, yCoord + 2, zCoord + dir.offsetZ * 2, PlasmaNetworkProvider.THE_PROVIDER); @@ -37,6 +67,19 @@ public class TileEntityFusionBreeder extends TileEntity { if(plasmaNode != null && plasmaNode.hasValidNet()) plasmaNode.net.addReceiver(this); } } + + public DirPos[] getConPos() { + ForgeDirection dir = ForgeDirection.getOrientation(this.getBlockMetadata() - 10); + ForgeDirection rot = dir.getRotation(ForgeDirection.UP); + + return new DirPos[] { + new DirPos(xCoord + dir.offsetX * 3, yCoord + 2, zCoord + dir.offsetZ * 3, dir), + new DirPos(xCoord + rot.offsetX * 3, yCoord, zCoord + rot.offsetZ * 3, rot), + new DirPos(xCoord - rot.offsetX * 3, yCoord, zCoord - rot.offsetZ * 3, rot.getOpposite()), + new DirPos(xCoord + dir.offsetX + rot.offsetX * 3, yCoord, zCoord + dir.offsetX + rot.offsetZ * 3, rot), + new DirPos(xCoord - dir.offsetX - rot.offsetX * 3, yCoord, zCoord - dir.offsetX - rot.offsetZ * 3, rot.getOpposite()) + }; + } @Override public void invalidate() { @@ -47,6 +90,34 @@ public class TileEntityFusionBreeder extends TileEntity { } } + @Override + public void serialize(ByteBuf buf) { + super.serialize(buf); + this.tanks[0].serialize(buf); + this.tanks[1].serialize(buf); + } + + @Override + public void deserialize(ByteBuf buf) { + super.deserialize(buf); + this.tanks[0].deserialize(buf); + this.tanks[1].deserialize(buf); + } + + @Override public FluidTank[] getReceivingTanks() { return new FluidTank[] {tanks[0]}; } + @Override public FluidTank[] getSendingTanks() { return new FluidTank[] {tanks[1]}; } + @Override public FluidTank[] getAllTanks() { return tanks; } + + @Override + public Container provideContainer(int ID, EntityPlayer player, World world, int x, int y, int z) { + return null; + } + + @Override + public Object provideGUI(int ID, EntityPlayer player, World world, int x, int y, int z) { + return null; + } + AxisAlignedBB bb = null; @Override diff --git a/src/main/java/com/hbm/tileentity/machine/fusion/TileEntityFusionKlystron.java b/src/main/java/com/hbm/tileentity/machine/fusion/TileEntityFusionKlystron.java index 48ab63193..e1853bb2d 100644 --- a/src/main/java/com/hbm/tileentity/machine/fusion/TileEntityFusionKlystron.java +++ b/src/main/java/com/hbm/tileentity/machine/fusion/TileEntityFusionKlystron.java @@ -34,7 +34,7 @@ import net.minecraftforge.common.util.ForgeDirection; public class TileEntityFusionKlystron extends TileEntityMachineBase implements IEnergyReceiverMK2, IFluidStandardReceiverMK2, IControlReceiver, IGUIProvider { protected GenNode klystronNode; - public static final long MAX_OUTPUT = 100_000_000; + public static final long MAX_OUTPUT = 1_000_000; public static final int AIR_CONSUMPTION = 2_500; public long outputTarget; public long output; diff --git a/src/main/java/com/hbm/tileentity/machine/fusion/TileEntityFusionTorus.java b/src/main/java/com/hbm/tileentity/machine/fusion/TileEntityFusionTorus.java index 95b4ab17c..f49edf19a 100644 --- a/src/main/java/com/hbm/tileentity/machine/fusion/TileEntityFusionTorus.java +++ b/src/main/java/com/hbm/tileentity/machine/fusion/TileEntityFusionTorus.java @@ -122,6 +122,7 @@ public class TileEntityFusionTorus extends TileEntityCooledBase implements IGUIP this.power = Library.chargeTEFromItems(slots, 0, power, this.getMaxPower()); + int receiverCount = 0; int collectors = 0; for(int i = 0; i < 4; i++) { @@ -133,9 +134,8 @@ public class TileEntityFusionTorus extends TileEntityCooledBase implements IGUIP for(Object o : plasmaNodes[i].net.receiverEntries.entrySet()) { Entry entry = (Entry) o; - if(entry.getKey() instanceof TileEntityFusionCollector) { - collectors++; - } + if(entry.getKey() instanceof IFusionPowerReceiver) receiverCount++; + if(entry.getKey() instanceof TileEntityFusionCollector) collectors++; break; } } @@ -163,6 +163,24 @@ public class TileEntityFusionTorus extends TileEntityCooledBase implements IGUIP this.fuelConsumption = factor; } + double outputIntensity = this.getOuputIntensity(receiverCount); + double outputFlux = recipe != null ? recipe.neutronFlux * factor : 0D; + + if(this.plasmaEnergy > 0) for(int i = 0; i < 4; i++) { + + if(plasmaNodes[i] != null && plasmaNodes[i].hasValidNet() && !plasmaNodes[i].net.receiverEntries.isEmpty()) { + + for(Object o : plasmaNodes[i].net.receiverEntries.entrySet()) { + Entry entry = (Entry) o; + + if(entry.getKey() instanceof IFusionPowerReceiver) { + long powerReceived = (long) Math.ceil(this.plasmaEnergy * outputIntensity); + ((IFusionPowerReceiver) entry.getKey()).receiveFusionPower(powerReceived, outputFlux); + } + } + } + } + this.networkPackNT(150); this.klystronEnergy = 0; @@ -185,6 +203,13 @@ public class TileEntityFusionTorus extends TileEntityCooledBase implements IGUIP } } + public static double getOuputIntensity(int receiverCount) { + if(receiverCount == 1) return 1D; // 100% + if(receiverCount == 2) return 0.625D; // 125% + if(receiverCount == 3) return 0.5D; // 150% + return 0.4375D; // 175% + } + public GenNode createNode(INetworkProvider provider, ForgeDirection dir) { GenNode node = UniNodespace.getNode(worldObj, xCoord + dir.offsetX * 7, yCoord + 2, zCoord + dir.offsetZ * 7, provider); if(node != null) return node; diff --git a/src/main/java/com/hbm/uninos/GenNode.java b/src/main/java/com/hbm/uninos/GenNode.java index 3e4b0925b..2d3ee43ab 100644 --- a/src/main/java/com/hbm/uninos/GenNode.java +++ b/src/main/java/com/hbm/uninos/GenNode.java @@ -7,6 +7,8 @@ public class GenNode { public BlockPos[] positions; public DirPos[] connections; + /** Quick reminder that this CAN and WILL be null for the first tick between the node being created + * and the nodepsace update loop establishing a network. always check hasValidNet beforehand! */ public N net; public boolean expired = false; public boolean recentlyChanged = true; diff --git a/src/main/java/com/hbm/world/gen/NTMWorldGenerator.java b/src/main/java/com/hbm/world/gen/NTMWorldGenerator.java index c6abdbc8b..dbf6922fa 100644 --- a/src/main/java/com/hbm/world/gen/NTMWorldGenerator.java +++ b/src/main/java/com/hbm/world/gen/NTMWorldGenerator.java @@ -1,8 +1,6 @@ package com.hbm.world.gen; -import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Random; @@ -26,6 +24,8 @@ import net.minecraft.world.World; import net.minecraft.world.biome.BiomeGenBase; import net.minecraft.world.chunk.IChunkProvider; import net.minecraft.world.gen.structure.StructureComponent.BlockSelector; +import net.minecraftforge.common.BiomeDictionary; +import net.minecraftforge.common.BiomeDictionary.Type; import net.minecraftforge.event.terraingen.InitMapGenEvent.EventType; import net.minecraftforge.event.terraingen.PopulateChunkEvent; import net.minecraftforge.event.terraingen.TerrainGen; @@ -34,48 +34,50 @@ import net.minecraftforge.event.world.WorldEvent; public class NTMWorldGenerator implements IWorldGenerator { boolean regTest = false; + + public static boolean isInvalidBiome(BiomeGenBase biome) { + return BiomeDictionary.isBiomeOfType(biome, Type.OCEAN) || BiomeDictionary.isBiomeOfType(biome, Type.RIVER); + } + + public static boolean isFlatBiome(BiomeGenBase biome) { + return biome.heightVariation <= 0.2F && !isInvalidBiome(biome) && BiomeDictionary.isBiomeOfType(biome, Type.SPARSE); + } public NTMWorldGenerator() { - final List invalidBiomes = Arrays.asList(new BiomeGenBase[] {BiomeGenBase.ocean, BiomeGenBase.river, BiomeGenBase.frozenOcean, BiomeGenBase.frozenRiver, BiomeGenBase.deepOcean}); - final List oceanBiomes = Arrays.asList(new BiomeGenBase[] { BiomeGenBase.ocean, BiomeGenBase.deepOcean }); - final List beachBiomes = Arrays.asList(new BiomeGenBase[] { BiomeGenBase.beach, BiomeGenBase.stoneBeach, BiomeGenBase.coldBeach }); - final List lighthouseBiomes = Arrays.asList(new BiomeGenBase[] { BiomeGenBase.ocean, BiomeGenBase.deepOcean, BiomeGenBase.beach, BiomeGenBase.stoneBeach, BiomeGenBase.coldBeach }); - final List flatbiomes = Arrays.asList(BiomeGenBase.plains,BiomeGenBase.icePlains,BiomeGenBase.desert, BiomeGenBase.forest, BiomeGenBase.taiga, BiomeGenBase.coldTaiga, BiomeGenBase.savanna, BiomeGenBase.savannaPlateau, BiomeGenBase.birchForest); - /// SPIRE /// NBTStructure.registerStructure(0, new SpawnCondition("spire") {{ - canSpawn = biome -> biome.heightVariation <= 0.05F && !invalidBiomes.contains(biome); + canSpawn = biome -> biome.heightVariation <= 0.05F && !isInvalidBiome(biome); structure = new JigsawPiece("spire", StructureManager.spire, -1); spawnWeight = StructureConfig.spireSpawnWeight; }}); NBTStructure.registerStructure(0, new SpawnCondition("features") {{ - canSpawn = biome -> !invalidBiomes.contains(biome); + canSpawn = biome -> !isInvalidBiome(biome); start = d -> new MapGenNTMFeatures.Start(d.getW(), d.getX(), d.getY(), d.getZ()); spawnWeight = StructureConfig.featuresSpawnWeight; }}); NBTStructure.registerStructure(0, new SpawnCondition("bunker") {{ - canSpawn = biome -> !invalidBiomes.contains(biome); + canSpawn = biome -> !isInvalidBiome(biome); start = d -> new BunkerStart(d.getW(), d.getX(), d.getY(), d.getZ()); spawnWeight = StructureConfig.bunkerSpawnWeight; }}); NBTStructure.registerStructure(0, new SpawnCondition("vertibird") {{ - canSpawn = biome -> !biome.canSpawnLightningBolt() && biome.temperature >= 2F; + canSpawn = biome -> !isInvalidBiome(biome) && BiomeDictionary.isBiomeOfType(biome, Type.SANDY); structure = new JigsawPiece("vertibird", StructureManager.vertibird, -3); spawnWeight = StructureConfig.vertibirdSpawnWeight; }}); NBTStructure.registerStructure(0, new SpawnCondition("crashed_vertibird") {{ - canSpawn = biome -> !biome.canSpawnLightningBolt() && biome.temperature >= 2F; + canSpawn = biome -> !isInvalidBiome(biome) && BiomeDictionary.isBiomeOfType(biome, Type.SANDY); structure = new JigsawPiece("crashed_vertibird", StructureManager.crashed_vertibird, -10); spawnWeight = StructureConfig.vertibirdCrashedSpawnWeight; }}); NBTStructure.registerStructure(0, new SpawnCondition("beached_patrol") {{ - canSpawn = beachBiomes::contains; + canSpawn = biome -> BiomeDictionary.isBiomeOfType(biome, Type.BEACH); structure = new JigsawPiece("beached_patrol", StructureManager.beached_patrol, -5); minHeight = 58; maxHeight = 67; @@ -83,14 +85,14 @@ public class NTMWorldGenerator implements IWorldGenerator { }}); NBTStructure.registerStructure(0, new SpawnCondition("aircraft_carrier") {{ - canSpawn = oceanBiomes::contains; + canSpawn = biome -> BiomeDictionary.isBiomeOfType(biome, Type.OCEAN); structure = new JigsawPiece("aircraft_carrier", StructureManager.aircraft_carrier, -6); maxHeight = 42; spawnWeight = StructureConfig.enableOceanStructures ? StructureConfig.aircraftCarrierSpawnWeight : 0; }}); NBTStructure.registerStructure(0, new SpawnCondition("oil_rig") {{ - canSpawn = biome -> biome == BiomeGenBase.deepOcean; + canSpawn = biome -> BiomeDictionary.isBiomeOfType(biome, Type.OCEAN) && biome.rootHeight >= -1.5F; structure = new JigsawPiece("oil_rig", StructureManager.oil_rig, -20); maxHeight = 12; minHeight = 11; @@ -98,7 +100,7 @@ public class NTMWorldGenerator implements IWorldGenerator { }}); NBTStructure.registerStructure(0, new SpawnCondition("lighthouse") {{ - canSpawn = lighthouseBiomes::contains; + canSpawn = biome -> BiomeDictionary.isBiomeOfType(biome, Type.OCEAN) || BiomeDictionary.isBiomeOfType(biome, Type.BEACH); structure = new JigsawPiece("lighthouse", StructureManager.lighthouse, -40); maxHeight = 29; minHeight = 28; @@ -106,7 +108,7 @@ public class NTMWorldGenerator implements IWorldGenerator { }}); NBTStructure.registerStructure(0, new SpawnCondition("dish") {{ - canSpawn = biome -> biome == BiomeGenBase.plains; + canSpawn = biome -> BiomeDictionary.isBiomeOfType(biome, Type.PLAINS); structure = new JigsawPiece("dish", StructureManager.dish, -10); minHeight = 53; maxHeight = 65; @@ -114,13 +116,13 @@ public class NTMWorldGenerator implements IWorldGenerator { }}); NBTStructure.registerStructure(0, new SpawnCondition("forestchem") {{ - canSpawn = biome -> biome.heightVariation <= 0.3F; + canSpawn = biome -> biome.heightVariation <= 0.3F && !isInvalidBiome(biome); structure = new JigsawPiece("forest_chem", StructureManager.forest_chem, -9); spawnWeight = StructureConfig.forestChemSpawnWeight; }}); NBTStructure.registerStructure(0, new SpawnCondition("labolatory") {{ - canSpawn = flatbiomes::contains; + canSpawn = biome -> isFlatBiome(biome); structure = new JigsawPiece("laboratory", StructureManager.laboratory, -10); minHeight = 53; maxHeight = 65; @@ -128,118 +130,118 @@ public class NTMWorldGenerator implements IWorldGenerator { }}); NBTStructure.registerStructure(0, new SpawnCondition("forest_post") {{ - canSpawn = biome -> biome.heightVariation <= 0.3F; + canSpawn = biome -> biome.heightVariation <= 0.3F && !isInvalidBiome(biome); structure = new JigsawPiece("forest_post", StructureManager.forest_post, -10); spawnWeight = StructureConfig.forestPostSpawnWeight; }}); NBTStructure.registerStructure(0, new SpawnCondition("radio") {{ - canSpawn = flatbiomes::contains; + canSpawn = biome -> isFlatBiome(biome); structure = new JigsawPiece("radio_house", StructureManager.radio_house, -6); spawnWeight = StructureConfig.radioSpawnWeight; }}); NBTStructure.registerStructure(0, new SpawnCondition("factory") {{ - canSpawn = flatbiomes::contains; + canSpawn = biome -> isFlatBiome(biome); structure = new JigsawPiece("factory", StructureManager.factory, -10); spawnWeight = StructureConfig.factorySpawnWeight; }}); NBTStructure.registerStructure(0, new SpawnCondition("crane") {{ - canSpawn = flatbiomes::contains; + canSpawn = biome -> isFlatBiome(biome); structure = new JigsawPiece("crane", StructureManager.crane, -9); spawnWeight = StructureConfig.craneSpawnWeight; }}); - + NBTStructure.registerStructure(0, new SpawnCondition("broadcaster_tower") {{ - canSpawn = flatbiomes::contains; + canSpawn = biome -> isFlatBiome(biome); structure = new JigsawPiece("broadcaster_tower", StructureManager.broadcasting_tower, -9); spawnWeight = StructureConfig.broadcastingTowerSpawnWeight; }}); NBTStructure.registerStructure(0, new SpawnCondition("plane1") {{ - canSpawn = biome -> biome.heightVariation <= 0.3F; + canSpawn = biome -> biome.heightVariation <= 0.3F && !isInvalidBiome(biome); structure = new JigsawPiece("crashed_plane_1", StructureManager.plane1, -5); spawnWeight = StructureConfig.plane1SpawnWeight; }}); NBTStructure.registerStructure(0, new SpawnCondition("plane2") {{ - canSpawn = biome -> biome.heightVariation <= 0.3F; + canSpawn = biome -> biome.heightVariation <= 0.3F && !isInvalidBiome(biome); structure = new JigsawPiece("crashed_plane_2", StructureManager.plane2, -8); spawnWeight = StructureConfig.plane2SpawnWeight; }}); NBTStructure.registerStructure(0, new SpawnCondition("desert_shack_1") {{ - canSpawn = biome -> biome == BiomeGenBase.desert; + canSpawn = biome -> BiomeDictionary.isBiomeOfType(biome, Type.SANDY); structure = new JigsawPiece("desert_shack_1", StructureManager.desert_shack_1, -7); spawnWeight = StructureConfig.desertShack1SpawnWeight; }}); NBTStructure.registerStructure(0, new SpawnCondition("desert_shack_2") {{ - canSpawn = biome -> biome == BiomeGenBase.desert; + canSpawn = biome -> BiomeDictionary.isBiomeOfType(biome, Type.SANDY); structure = new JigsawPiece("desert_shack_2", StructureManager.desert_shack_2, -7); spawnWeight = StructureConfig.desertShack2SpawnWeight; }}); NBTStructure.registerStructure(0, new SpawnCondition("desert_shack_3") {{ - canSpawn = biome -> biome == BiomeGenBase.desert; + canSpawn = biome -> BiomeDictionary.isBiomeOfType(biome, Type.SANDY); structure = new JigsawPiece("desert_shack_3", StructureManager.desert_shack_3, -5); spawnWeight = StructureConfig.desertShack3SpawnWeight; }}); NBTStructure.registerStructure(0, new SpawnCondition("ruinA") {{ - canSpawn = biome -> !invalidBiomes.contains(biome) && biome.canSpawnLightningBolt(); + canSpawn = biome -> !isInvalidBiome(biome) && biome.canSpawnLightningBolt(); structure = new JigsawPiece("NTMRuinsA", StructureManager.ntmruinsA, -1) {{conformToTerrain = true;}}; spawnWeight = StructureConfig.enableRuins ? StructureConfig.ruinsASpawnWeight : 0; }}); NBTStructure.registerStructure(0, new SpawnCondition("ruinB") {{ - canSpawn = biome -> !invalidBiomes.contains(biome) && biome.canSpawnLightningBolt(); + canSpawn = biome -> !isInvalidBiome(biome) && biome.canSpawnLightningBolt(); structure = new JigsawPiece("NTMRuinsB", StructureManager.ntmruinsB, -1) {{conformToTerrain = true;}}; spawnWeight = StructureConfig.enableRuins ? StructureConfig.ruinsBSpawnWeight : 0; }}); NBTStructure.registerStructure(0, new SpawnCondition("ruinC") {{ - canSpawn = biome -> !invalidBiomes.contains(biome) && biome.canSpawnLightningBolt(); + canSpawn = biome -> !isInvalidBiome(biome) && biome.canSpawnLightningBolt(); structure = new JigsawPiece("NTMRuinsC", StructureManager.ntmruinsC, -1) {{conformToTerrain = true;}}; spawnWeight = StructureConfig.enableRuins ? StructureConfig.ruinsCSpawnWeight : 0; }}); NBTStructure.registerStructure(0, new SpawnCondition("ruinD") {{ - canSpawn = biome -> !invalidBiomes.contains(biome) && biome.canSpawnLightningBolt(); + canSpawn = biome -> !isInvalidBiome(biome) && biome.canSpawnLightningBolt(); structure = new JigsawPiece("NTMRuinsD", StructureManager.ntmruinsD, -1) {{conformToTerrain = true;}}; spawnWeight = StructureConfig.enableRuins ? StructureConfig.ruinsDSpawnWeight : 0; }}); NBTStructure.registerStructure(0, new SpawnCondition("ruinE") {{ - canSpawn = biome -> !invalidBiomes.contains(biome) && biome.canSpawnLightningBolt(); + canSpawn = biome -> !isInvalidBiome(biome) && biome.canSpawnLightningBolt(); structure = new JigsawPiece("NTMRuinsE", StructureManager.ntmruinsE, -1) {{conformToTerrain = true;}}; spawnWeight = StructureConfig.enableRuins ? StructureConfig.ruinsESpawnWeight : 0; }}); NBTStructure.registerStructure(0, new SpawnCondition("ruinF") {{ - canSpawn = biome -> !invalidBiomes.contains(biome) && biome.canSpawnLightningBolt(); + canSpawn = biome -> !isInvalidBiome(biome) && biome.canSpawnLightningBolt(); structure = new JigsawPiece("NTMRuinsF", StructureManager.ntmruinsF, -1) {{conformToTerrain = true;}}; spawnWeight = StructureConfig.enableRuins ? StructureConfig.ruinsFSpawnWeight : 0; }}); NBTStructure.registerStructure(0, new SpawnCondition("ruinG") {{ - canSpawn = biome -> !invalidBiomes.contains(biome) && biome.canSpawnLightningBolt(); + canSpawn = biome -> !isInvalidBiome(biome) && biome.canSpawnLightningBolt(); structure = new JigsawPiece("NTMRuinsG", StructureManager.ntmruinsG, -1) {{conformToTerrain = true;}}; spawnWeight = StructureConfig.enableRuins ? StructureConfig.ruinsGSpawnWeight : 0; }}); NBTStructure.registerStructure(0, new SpawnCondition("ruinH") {{ - canSpawn = biome -> !invalidBiomes.contains(biome) && biome.canSpawnLightningBolt(); + canSpawn = biome -> !isInvalidBiome(biome) && biome.canSpawnLightningBolt(); structure = new JigsawPiece("NTMRuinsH", StructureManager.ntmruinsH, -1) {{conformToTerrain = true;}}; spawnWeight = StructureConfig.enableRuins ? StructureConfig.ruinsHSpawnWeight : 0; }}); NBTStructure.registerStructure(0, new SpawnCondition("ruinI") {{ - canSpawn = biome -> !invalidBiomes.contains(biome) && biome.canSpawnLightningBolt(); + canSpawn = biome -> !isInvalidBiome(biome) && biome.canSpawnLightningBolt(); structure = new JigsawPiece("NTMRuinsI", StructureManager.ntmruinsI, -1) {{conformToTerrain = true;}}; spawnWeight = StructureConfig.enableRuins ? StructureConfig.ruinsISpawnWeight : 0; }}); NBTStructure.registerStructure(0, new SpawnCondition("ruinJ") {{ - canSpawn = biome -> !invalidBiomes.contains(biome) && biome.canSpawnLightningBolt(); + canSpawn = biome -> !isInvalidBiome(biome) && biome.canSpawnLightningBolt(); structure = new JigsawPiece("NTMRuinsJ", StructureManager.ntmruinsJ, -1) {{conformToTerrain = true;}}; spawnWeight = StructureConfig.enableRuins ? StructureConfig.ruinsJSpawnWeight : 0; }}); NBTStructure.registerNullWeight(0, StructureConfig.plainsNullWeight, biome -> biome == BiomeGenBase.plains); - NBTStructure.registerNullWeight(0, StructureConfig.oceanNullWeight, oceanBiomes::contains); + NBTStructure.registerNullWeight(0, StructureConfig.oceanNullWeight, biome -> BiomeDictionary.isBiomeOfType(biome, Type.OCEAN)); Map bricks = new HashMap() {{ put(ModBlocks.meteor_brick, new MeteorBricks()); diff --git a/src/main/resources/assets/hbm/lang/en_US.lang b/src/main/resources/assets/hbm/lang/en_US.lang index f82a81730..ffbb75370 100644 --- a/src/main/resources/assets/hbm/lang/en_US.lang +++ b/src/main/resources/assets/hbm/lang/en_US.lang @@ -1273,6 +1273,7 @@ general.na=N/A gui.recipe.duration=Duration gui.recipe.consumption=Consumption +gui.recipe.fusionFlux=Output Neutron Flux gui.recipe.fusionIn=Klystron Input Energy gui.recipe.fusionOut=Plasma Output Energy gui.recipe.input=Input diff --git a/src/main/resources/assets/hbm/textures/gui/reactors/gui_fusion_breeder.png b/src/main/resources/assets/hbm/textures/gui/reactors/gui_fusion_breeder.png new file mode 100644 index 0000000000000000000000000000000000000000..f50d801d8965e7e11a7f7738e4a903277f789a2b GIT binary patch literal 3055 zcmbVOc|4T+8vo50W^jd$Ejv?=5-CmznIUUrOPZ2KrD2jKBC^a#Wu#-LLZvKaSJV(1 zOIfooWlET=lOOoI1jjpI0VY;X2;LQja3=vEoM&Zf>=c|iH;nR>_mFK~v`|xq z-5A%Gr01wLpZR*cgWmn1GrH6=SEAuVRe$|jdZXFNt$r%0SM9P)X4G;>=^9$Dsw?my zx#8U7S{((}iFCavl}hcVm1>WNExKK>rA){_99VUl9V$mH0jOMUeT+RCj>!L1 z$OOa?&z&V*r;Ow{>|{Gi(gH#6ST#%;xTQDIn6ne*uSgu4^l3pL(O|L|D+bW>MG_PQ z1dMkc+Hi?pFfb|u0ea>D#EApqS)Pm8ehkX_{9vx?0|rY_*J!uiFE7&ckit@*a~vJv z`rTh!@Z~b65=*5i4FB;jsG6`Q*Bjd&QNq+U0ga*^f>K)JIrapdZa?>sGiS*U_xX-= zvA(azmRjp4oyUCHwa^bIrY3IN$+CT%yjFuN->$kU0@Yw&hdhUfVUL_wa8T1^*)wWh z@<*m}8q}Xd+)i%|S^ma;-LMc;9n^Hu&){88f>Fk*Abg_ zU)Pf-c{m3L2U|Yl%YnGVqO3>#evr{GfTmhHPAK5;Z`S%cDk$5E$5K#Nk`@?@UTxT|;{p zuP-By2n@vc0!7_T=YnUTc6T;9V zBTy5+bIiNeIe1~0SHA%8YIBh?A^r%_PP)~r2wk~-_&lGo(`35i`l&GLLG-l%Fv#n> zd71Lnc2mn*R}oA4LosI#@6W1YWKZvM>4yVk>^++F zLrRf@94OijFOoq0RZ-8((^glbmwJ*dwkiIuC5uJrKwSC->b82drA}21s6I{UL|***ESV@2{fJZM=b}ycHc&8Pf9}D`UrF zfc_%SMmX{1HS1w!;XLmj^f)nhlgem5g`SlHy8Y{KPC{LdpK>fmCZ=&r77qy$3k#Jd z==A0)YRfvZ#uP_+XQa4w`C~asE2ZGQD7uf|T-_OO4T_b?k(RSf+VQCqxlhgR=-g(BVE;!M` zLofu6#yBm~ZW0t8@V^$`mH+;+CM##id__-Y%^}T^Pq}b3Hcj_x-tPs;hDKke4XxxB zDbdy`c!HF+?TijF=aFdC!?)1-(;@qcw5~LFcf} z>aTb83M#cH1^ps!&o2qFpOCzI5r13gag6jzMLD8_te(x;Axx||hn8I0(ZINOofwn~ zLl5vPrB3OF^^!%h5kgL_1950PZhM237RM^o$V^o8kRT{Fc>7j|Y3K4<;()GWxQczE zT5WAwgW0|OVCgI&iM^x20!06NWFGI(&Exy|FuYOAjE3);zEDTH4yDd6%+E`8@1&28 zkDKP)88LX9^(1aux?gKHo3XJ?0B}g^fJ$SG0j56Yb>=m0BD=l4{g5c^PXFX&9zrD{ zHq>OX@lJL&QXE%Qg-O7GOVz{lIDtELGc)-lKL-az^LhR(1_WEV1>tuK0C^+;%?MDp z8w!5nK7HH8AG}H*_=s}z@UZCY?DUKd!ud?qN5KQgQSN6^GVUH89wka;Wb&^(qvD`} z4!O~_;0C>l=sB1xBSBA8|s0aU>U}h1f2J{cc7x!F-L3PhqWU zC}}^nE6`j@b+yY-B0%bym=YWdcbZpa+=Ej0Rvo@4tK^fc~^rw-?t zl2bUsFK-ay*VrcMe{zP@`}9Bb{9KiP@wU(vU_OaSsAt^Ote2PgW)e_6fHDjo8+&dN zL+t=2`{b^k7!uX4;9*!Uh=;^sb|m2UbyTcSX}BTf{-rPcf5!a7u7hzzv!VrCbMSX< PHXc}+*_xJ^xLy4xBN$sz literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/hbm/textures/gui/reactors/gui_fusion_klystron.png b/src/main/resources/assets/hbm/textures/gui/reactors/gui_fusion_klystron.png index ec493582831835ef805a5b6267a15a3e2a6e51f9..7ec53139f4769783c738f77dcacaa89ee903404a 100644 GIT binary patch delta 2964 zcmaJ?c{tQ-8~)8iA+nX28eExDi1C#rW2WOb{~sigV}{s7;1&u_)Gb!5CMS3_}lO}$O4fzEv@w$)c8!n$>4<1b#b;L{b$ zTboyh$`HjaC1|RnqvM=$$}+1}58W8E9!N2_h|tU4Sqcsf?fsfGSs(tQe-klP(^Ar_ zby)f5*r2YZq~5q_eH^jY{h~0MFkE^ajJ1y0n7E-Q>DwRih&z?Z=*rY{$j1_PTlmj( z(VZ9rar69bpFd@VQ{Z~~WD=s8AAy+&F)Cn%RUO=|cC*&~itq^==RqcuO-xK4IZMv3 zJZ3qWsgACBR_7-t%NW39zI-U>Y6Av4)p zJVBzcz<@QYm$~kb|BDy=T!Id~{Z#dAD3EnynS?b1qSFV>0Z=IFxy536;9`>1Sk7;K zlDW=W^h0xrKc7{e{SE=DpPQ2&J`|*3(ayjNf8n1F0xbZ&3q$EJCmAuvw>#Gl#qJW4 zWp@lg9aIc#O0!*SOx*%NDdG9Y|!wI_Uo_WQ6}`tPGiYn zv9}sotx?Z+1g)9@NhJMAB3p1zathO(Y#D70wX>YA3$P{CQ)5nAPEr7cDSkFi>@L{= zu(A=SfZ-dExdW2w5NBY^R-E) `_W1QbEez}@>&>O!|&mcIXk{y(s)q9S)hY0?QL z-C-q8vNNIgbYwm{!gJdNNasT>5g+A`^Pm&*^R8Lv+dqfWD+B^T&G|OvTK8lWG}#gg zbie>FSP%e`yubdv1CYKU10e59iNXMALu!d)7yw=riQ=Db^Ky?l~+?mF3 zDLINB`|u$RVE{``KwOMbT}|GRcXDxp0Nubp=O|}9i(D%W1WeiO_3-hDDSi7|_w>_(6i3t7`IVBnS9OVSgmwZh zIFtCX#>9lH-uvnpX?FI;L^IK7SoU~kmsYxcmi$LMmpI1FQn9-cV-r&B^i+iTKRJeGXRg*D9R267NyxFM4B|f+cfeIZIzF{VmvCHbSKHma0=c z%SVQ`D;MBb0u7o!aApTmS{fToZl7I!U*HgXYG-OBex?Cwl9Sa!$Pv4Xz4S2NsFbi< zo5A?6RE7n1KGBSXDj(*T1ssk4X|D%$uz@gW#2i{$Z&{s4%~Wc>jqfYM=(?D)Qc}O5 zI|#3iGBBNr;P=7fcgGWDk-Xjub5fRzQ3^&X-FeXYEP>j|XHf-bZpS+;Mr~%5`ZF*_ z&ZdRcx0X8RX1L|&t>^;UeOr@5eDtw+;>PmA0GmB|ur4GzaXpdKIw;idg8W1*#GB&0lO3TW=o0$iK84j1fjBC`!WpfB08T_?1>8XB*i zw*Wb%BTF%B{Do-t0Qb$YKuyU*z4Sm%BflZy;V-@?b8_>X56&v=P6Vq46-mU*;ff5U zgF~2W%S&@Fl$un{t`Ci5IW&HIH)o`BZ@@d@RYYN)M_7Cq^Pxz_g>5-=Iw^X!yxnc(*;a=}asu}8T5{GpUirfi%rdarG zx+rBiOPG;3m7j_-ypZmNS;UJ;xo3z(C!$b=)`A~=r*A_a z{|z2FkfM42&zFkUeXZd8PK==;n1Rzm?|vR}Sj-AKvG&`)H23JwnL zJ`Qv9i(YX!|CX~K{EmFes+T|Ija%6T{8*^xx}=KZNljkidL$%>2u<8aiPF~ARzQ2@ z<>JMBRx~wSad`Yut>JqK{;yla+LSzf=}hwAw#{Sok!B-x(iUa=;#mkIiT0DUmhsCt zY;LcG&=e;Z6cjYZVim&2?tSbz6xt-ugp(DbgDPrkYu#9_4GqNtLG0KQ`fK)z*3eC3 zaoY4=11phD=zJFd!^6Wh4Gk(Nxv?kk?rVJ;7xAhVaXJh9@x%yQ^|3eSP>Fc4vGH-5 z$Z2Fw5G;(6P|*IKt2Hm+@p;}dv{or48fUMD+OmWdDx!a1-gJs(&8dUzFx%Xl^%`>Q zZflgtcVWY{a;amYJjFA!|KRG6M)6|Ms=Fwt_=^*Om-2rsONl5?VL}HSmBv(>w2=wZ zWovUx#a~^WDQjyFlLC}&pn$Xn#A~_!lf|*U zjS_Bd7)-dRja#$O2*lT!yVaGI`stP=MkQd3d0>%3BkXUBL~cT8{nD3}Usnis6?3no U*S`&w`9Toc+R>`)oL9oX0m=cm@&Et; delta 2944 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 diff --git a/src/main/resources/assets/hbm/textures/gui/reactors/gui_fusion_torus.png b/src/main/resources/assets/hbm/textures/gui/reactors/gui_fusion_torus.png index b0f8722d2423f39beb3d70bf533ceb5287e38fbb..48b84ef87f121b9caadb58081697690414b47a0e 100644 GIT binary patch literal 4931 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 XDAf)98p!-927sQHk!G2Oee{0;xq>!C literal 4927 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 g*|2{g=f