From 4aaa092db997eb8e7bd5938f692e5aa2f4ad129e Mon Sep 17 00:00:00 2001 From: DianeXD Date: Wed, 29 Jun 2022 20:45:17 +0800 Subject: [PATCH] Add NEI support for Genetics --- src/main/java/binnie/core/nei/NEIUtils.java | 39 +++ .../binnie/core/nei/PositionedFluidTank.java | 138 ++++++++++ .../binnie/core/nei/PositionedStackAdv.java | 50 ++++ .../binnie/core/nei/RecipeHandlerBase.java | 212 +++++++++++++++ src/main/java/binnie/genetics/Genetics.java | 2 + .../binnie/genetics/api/IIncubatorRecipe.java | 17 ++ .../machine/acclimatiser/Acclimatiser.java | 4 +- .../genetics/machine/incubator/Incubator.java | 118 +++------ .../incubator/IncubatorComponentLogic.java | 241 +++++++++--------- .../machine/incubator/IncubatorRecipe.java | 178 +++++++------ .../incubator/IncubatorRecipeLarvae.java | 29 +++ .../nei/AcclimatiserRecipeHandler.java | 184 +++++++++++++ .../genetics/nei/AnalyserRecipeHandler.java | 169 ++++++++++++ .../genetics/nei/DatabaseRecipeHandler.java | 142 +++++++++++ .../genetics/nei/GenepoolRecipeHandler.java | 193 ++++++++++++++ .../java/binnie/genetics/nei/IMCForNEI.java | 58 +++++ .../genetics/nei/IncubatorRecipeHandler.java | 168 ++++++++++++ .../genetics/nei/InoculatorRecipeHandler.java | 187 ++++++++++++++ .../genetics/nei/IsolatorRecipeHandler.java | 203 +++++++++++++++ .../genetics/nei/NEIGeneticsConfig.java | 39 +++ .../nei/PolymeriserRecipeHandler.java | 200 +++++++++++++++ .../genetics/nei/SequencerRecipeHandler.java | 116 +++++++++ .../genetics/nei/SplicerRecipeHandler.java | 177 +++++++++++++ .../resources/assets/genetics/lang/en_US.lang | 9 + .../textures/gui/nei/acclimatiser.png | Bin 0 -> 9892 bytes .../genetics/textures/gui/nei/analyser.png | Bin 0 -> 12174 bytes .../genetics/textures/gui/nei/database.png | Bin 0 -> 7462 bytes .../genetics/textures/gui/nei/genepool.png | Bin 0 -> 8216 bytes .../genetics/textures/gui/nei/incubator.png | Bin 0 -> 8101 bytes .../genetics/textures/gui/nei/inoculator.png | Bin 0 -> 8023 bytes .../genetics/textures/gui/nei/isolator.png | Bin 0 -> 8323 bytes .../genetics/textures/gui/nei/polymeriser.png | Bin 0 -> 8488 bytes .../genetics/textures/gui/nei/sequencer.png | Bin 0 -> 7747 bytes .../genetics/textures/gui/nei/splicer.png | Bin 0 -> 7573 bytes 34 files changed, 2598 insertions(+), 275 deletions(-) create mode 100644 src/main/java/binnie/core/nei/NEIUtils.java create mode 100644 src/main/java/binnie/core/nei/PositionedFluidTank.java create mode 100644 src/main/java/binnie/core/nei/PositionedStackAdv.java create mode 100644 src/main/java/binnie/core/nei/RecipeHandlerBase.java create mode 100644 src/main/java/binnie/genetics/machine/incubator/IncubatorRecipeLarvae.java create mode 100644 src/main/java/binnie/genetics/nei/AcclimatiserRecipeHandler.java create mode 100644 src/main/java/binnie/genetics/nei/AnalyserRecipeHandler.java create mode 100644 src/main/java/binnie/genetics/nei/DatabaseRecipeHandler.java create mode 100644 src/main/java/binnie/genetics/nei/GenepoolRecipeHandler.java create mode 100644 src/main/java/binnie/genetics/nei/IMCForNEI.java create mode 100644 src/main/java/binnie/genetics/nei/IncubatorRecipeHandler.java create mode 100644 src/main/java/binnie/genetics/nei/InoculatorRecipeHandler.java create mode 100644 src/main/java/binnie/genetics/nei/IsolatorRecipeHandler.java create mode 100644 src/main/java/binnie/genetics/nei/NEIGeneticsConfig.java create mode 100644 src/main/java/binnie/genetics/nei/PolymeriserRecipeHandler.java create mode 100644 src/main/java/binnie/genetics/nei/SequencerRecipeHandler.java create mode 100644 src/main/java/binnie/genetics/nei/SplicerRecipeHandler.java create mode 100644 src/main/resources/assets/genetics/textures/gui/nei/acclimatiser.png create mode 100644 src/main/resources/assets/genetics/textures/gui/nei/analyser.png create mode 100644 src/main/resources/assets/genetics/textures/gui/nei/database.png create mode 100644 src/main/resources/assets/genetics/textures/gui/nei/genepool.png create mode 100644 src/main/resources/assets/genetics/textures/gui/nei/incubator.png create mode 100644 src/main/resources/assets/genetics/textures/gui/nei/inoculator.png create mode 100644 src/main/resources/assets/genetics/textures/gui/nei/isolator.png create mode 100644 src/main/resources/assets/genetics/textures/gui/nei/polymeriser.png create mode 100644 src/main/resources/assets/genetics/textures/gui/nei/sequencer.png create mode 100644 src/main/resources/assets/genetics/textures/gui/nei/splicer.png diff --git a/src/main/java/binnie/core/nei/NEIUtils.java b/src/main/java/binnie/core/nei/NEIUtils.java new file mode 100644 index 00000000..8e31e805 --- /dev/null +++ b/src/main/java/binnie/core/nei/NEIUtils.java @@ -0,0 +1,39 @@ +package binnie.core.nei; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.*; + +public class NEIUtils { + public static FluidStack getFluidStack(ItemStack stack) { + if (stack != null) { + FluidStack fluidStack = null; + if (stack.getItem() instanceof IFluidContainerItem) { + fluidStack = ((IFluidContainerItem) stack.getItem()).getFluid(stack); + } + + if (fluidStack == null) { + fluidStack = FluidContainerRegistry.getFluidForFilledItem(stack); + } + + if (fluidStack == null && Block.getBlockFromItem(stack.getItem()) instanceof IFluidBlock) { + Fluid fluid = ((IFluidBlock) Block.getBlockFromItem(stack.getItem())).getFluid(); + if (fluid != null) { + fluidStack = new FluidStack(fluid, 1000); + } + } + + return fluidStack; + } else { + return null; + } + } + + public static boolean areFluidsSameType(FluidStack fluidStack1, FluidStack fluidStack2) { + if (fluidStack1 != null && fluidStack2 != null) { + return fluidStack1.getFluid() == fluidStack2.getFluid(); + } else { + return false; + } + } +} diff --git a/src/main/java/binnie/core/nei/PositionedFluidTank.java b/src/main/java/binnie/core/nei/PositionedFluidTank.java new file mode 100644 index 00000000..226d60c3 --- /dev/null +++ b/src/main/java/binnie/core/nei/PositionedFluidTank.java @@ -0,0 +1,138 @@ +package binnie.core.nei; + +import codechicken.lib.gui.GuiDraw; +import codechicken.nei.recipe.GuiCraftingRecipe; +import codechicken.nei.recipe.GuiUsageRecipe; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.IIcon; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTank; +import org.lwjgl.opengl.GL11; + +import java.awt.*; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +public class PositionedFluidTank { + + public FluidTank[] tanks; + public FluidTank tank; + public Rectangle position; + public String overlayTexture; + public Point overlayTexturePos; + public boolean flowingTexture = false; + public boolean showAmount = true; + public boolean perTick = false; + + public PositionedFluidTank(FluidTank[] tanks, Rectangle position, String overlayTexture, Point overlayTexturePos) { + this.position = position; + this.tanks = tanks; + this.tank = tanks[0]; + this.overlayTexture = overlayTexture; + this.overlayTexturePos = overlayTexturePos; + } + + public PositionedFluidTank(Collection fluids, int capacity, Rectangle position, String overlayTexture, Point overlayTexturePos) { + this(createFluidTanks(capacity, fluids), position, overlayTexture, overlayTexturePos); + } + + public PositionedFluidTank(FluidStack fluid, int capacity, Rectangle position, String overlayTexture, Point overlayTexturePos) { + this(createFluidTanks(capacity, Collections.singletonList(fluid)), position, overlayTexture, overlayTexturePos); + } + + public PositionedFluidTank(FluidStack fluid, int capacity, Rectangle position) { + this(fluid, capacity, position, null, null); + } + + private static FluidTank[] createFluidTanks(int capacity, Collection fluidStacks) { + FluidTank[] tanks = new FluidTank[fluidStacks.size()]; + int i = 0; + for (FluidStack fluidStack : fluidStacks) { + tanks[i++] = new FluidTank(fluidStacks != null ? fluidStack.copy() : null, capacity); + } + return tanks; + } + + public List handleTooltip(List currenttip) { + if (this.tank == null || this.tank.getFluid() == null || this.tank.getFluid().getFluid() == null || this.tank.getFluid().amount <= 0) { + return currenttip; + } + currenttip.add(this.tank.getFluid().getLocalizedName()); + if (this.showAmount) { + currenttip.add(EnumChatFormatting.GRAY.toString() + this.tank.getFluid().amount + (this.perTick ? " mB/t" : " mB")); + } + return currenttip; + } + + public boolean transfer(boolean usage) { + if (this.tank.getFluid() != null && this.tank.getFluid().amount > 0) { + if (usage) { + return GuiUsageRecipe.openRecipeGui("liquid", this.tank.getFluid()); + } else { + return GuiCraftingRecipe.openRecipeGui("liquid", this.tank.getFluid()); + } + } + return false; + } + + public void draw() { + if (this.tank == null || this.tank.getFluid() == null || this.tank.getFluid().getFluid() == null || this.tank.getFluid().amount <= 0) { + return; + } + final IIcon fluidIcon; + if (this.flowingTexture && this.tank.getFluid().getFluid().getFlowingIcon() != null) { + fluidIcon = this.tank.getFluid().getFluid().getFlowingIcon(); + } else if (this.tank.getFluid().getFluid().getStillIcon() != null) { + fluidIcon = this.tank.getFluid().getFluid().getStillIcon(); + } else { + return; + } + + GuiDraw.changeTexture(TextureMap.locationBlocksTexture); + int color = this.tank.getFluid().getFluid().getColor(this.tank.getFluid()); + GL11.glColor3ub((byte) (color >> 16 & 0xFF), (byte) (color >> 8 & 0xFF), (byte) (color & 0xFF)); + + int amount = Math.max(Math.min(this.position.height, this.tank.getFluid().amount * this.position.height / this.tank.getCapacity()), 1); + int posY = this.position.y + this.position.height - amount; + + for (int i = 0; i < this.position.width; i += 16) { + for (int j = 0; j < amount; j += 16) { + int drawWidth = Math.min(this.position.width - i, 16); + int drawHeight = Math.min(amount - j, 16); + + int drawX = this.position.x + i; + int drawY = posY + j; + + double minU = fluidIcon.getMinU(); + double maxU = fluidIcon.getMaxU(); + double minV = fluidIcon.getMinV(); + double maxV = fluidIcon.getMaxV(); + + Tessellator tessellator = Tessellator.instance; + tessellator.startDrawingQuads(); + tessellator.addVertexWithUV(drawX, drawY + drawHeight, 0, minU, minV + (maxV - minV) * drawHeight / 16F); + tessellator.addVertexWithUV(drawX + drawWidth, drawY + drawHeight, 0, minU + (maxU - minU) * drawWidth / 16F, minV + (maxV - minV) * drawHeight / 16F); + tessellator.addVertexWithUV(drawX + drawWidth, drawY, 0, minU + (maxU - minU) * drawWidth / 16F, minV); + tessellator.addVertexWithUV(drawX, drawY, 0, minU, minV); + tessellator.draw(); + } + } + + if (this.overlayTexture != null && this.overlayTexturePos != null) { + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + GuiDraw.changeTexture(this.overlayTexture); + GuiDraw.drawTexturedModalRect(this.position.x, this.position.y, this.overlayTexturePos.x, this.overlayTexturePos.y, this.position.width, this.position.height); + } + } + + public void setPermutationToRender(int index) { + this.tank = this.tanks[index]; + } + + public int getPermutationCount() { + return this.tanks.length; + } +} diff --git a/src/main/java/binnie/core/nei/PositionedStackAdv.java b/src/main/java/binnie/core/nei/PositionedStackAdv.java new file mode 100644 index 00000000..d1242ae4 --- /dev/null +++ b/src/main/java/binnie/core/nei/PositionedStackAdv.java @@ -0,0 +1,50 @@ +package binnie.core.nei; + +import codechicken.nei.ItemList; +import codechicken.nei.PositionedStack; +import codechicken.nei.recipe.GuiRecipe; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +public class PositionedStackAdv extends PositionedStack { + + private final List tooltip = new ArrayList<>(); + + public PositionedStackAdv(Object object, int x, int y) { + super(object, x, y); + } + + public PositionedStackAdv(Object object, int x, int y, List tooltip) { + super(object, x, y); + this.addToTooltip(tooltip); + } + + public Rectangle getRect() { + return new Rectangle(this.relx - 1, this.rely - 1, 18, 18); + } + + public List handleTooltip(GuiRecipe guiRecipe, List currenttip) { + if (!this.tooltip.isEmpty()) { + for (String tip : this.tooltip) { + currenttip.add(tip); + } + } + return currenttip; + } + + public PositionedStackAdv addToTooltip(List lines) { + for (String tip : lines) { + this.tooltip.add(tip); + } + return this; + } + + public PositionedStackAdv addToTooltip(String line) { + this.tooltip.add(line); + return this; + } +} diff --git a/src/main/java/binnie/core/nei/RecipeHandlerBase.java b/src/main/java/binnie/core/nei/RecipeHandlerBase.java new file mode 100644 index 00000000..b1971cec --- /dev/null +++ b/src/main/java/binnie/core/nei/RecipeHandlerBase.java @@ -0,0 +1,212 @@ +package binnie.core.nei; + +import codechicken.lib.gui.GuiDraw; +import codechicken.nei.NEIClientConfig; +import codechicken.nei.PositionedStack; +import codechicken.nei.guihook.GuiContainerManager; +import codechicken.nei.recipe.GuiRecipe; +import codechicken.nei.recipe.TemplateRecipeHandler; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; +import org.lwjgl.opengl.GL11; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +public abstract class RecipeHandlerBase extends TemplateRecipeHandler { + + public void prepare() { + } + + public void changeToGuiTexture() { + GuiDraw.changeTexture(this.getGuiTexture()); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + } + + public void addTransferRect(int x, int y, int width, int height) { + this.transferRects.add(new RecipeTransferRect(new Rectangle(x, y, width, height), this.getOverlayIdentifier())); + } + + @Override + public void drawForeground(int recipe) { + super.drawForeground(recipe); + this.drawFluidTanks(recipe); + this.changeToGuiTexture(); + } + + @Override + public void loadCraftingRecipes(String outputId, Object... results) { + if (outputId.equals("liquid") && results[0] instanceof FluidStack && ((FluidStack) results[0]).getFluid() != null) { + this.loadCraftingRecipes((FluidStack) results[0]); + } else if (outputId.equals(this.getOverlayIdentifier())) { + this.loadAllRecipes(); + } else { + super.loadCraftingRecipes(outputId, results); + } + } + + public void loadAllRecipes() { + } + + @Override + public void loadCraftingRecipes(ItemStack result) { + FluidStack fluid = NEIUtils.getFluidStack(result); + if (fluid != null && fluid.getFluid() != null) { + this.loadCraftingRecipes(fluid); + } + } + + public void loadCraftingRecipes(FluidStack result) { + } + + @Override + public void loadUsageRecipes(String inputId, Object... ingredients) { + if (inputId.equals("liquid") && ingredients[0] instanceof FluidStack && ((FluidStack) ingredients[0]).getFluid() != null) { + this.loadUsageRecipes((FluidStack) ingredients[0]); + } else { + super.loadUsageRecipes(inputId, ingredients); + } + } + + @Override + public void loadUsageRecipes(ItemStack ingred) { + FluidStack fluid = NEIUtils.getFluidStack(ingred); + if (fluid != null && fluid.getFluid() != null) { + this.loadUsageRecipes(fluid); + } + } + + public void loadUsageRecipes(FluidStack ingredient) { + } + + @Override + public List handleTooltip(GuiRecipe guiRecipe, List currenttip, int recipe) { + super.handleTooltip(guiRecipe, currenttip, recipe); + CachedBaseRecipe crecipe = (CachedBaseRecipe) this.arecipes.get(recipe); + if (GuiContainerManager.shouldShowTooltip(guiRecipe)) { + Point mouse = GuiDraw.getMousePosition(); + Point offset = guiRecipe.getRecipePosition(recipe); + Point relMouse = new Point(mouse.x - (guiRecipe.width - 176) / 2 - offset.x, mouse.y - (guiRecipe.height - Math.min(Math.max(guiRecipe.height - 68, 166), 370)) / 2 - 10 - offset.y); + currenttip = this.provideTooltip(guiRecipe, currenttip, crecipe, relMouse); + } + return currenttip; + } + + public List provideTooltip(GuiRecipe guiRecipe, List currenttip, CachedBaseRecipe crecipe, Point relMouse) { + if (crecipe.getFluidTanks() != null) { + for (PositionedFluidTank tank : crecipe.getFluidTanks()) { + if (tank.position.contains(relMouse)) { + tank.handleTooltip(currenttip); + } + } + } + return currenttip; + } + + @Override + public List handleItemTooltip(GuiRecipe guiRecipe, ItemStack itemStack, List currenttip, int recipe) { + super.handleItemTooltip(guiRecipe, itemStack, currenttip, recipe); + CachedBaseRecipe crecipe = (CachedBaseRecipe) this.arecipes.get(recipe); + Point mouse = GuiDraw.getMousePosition(); + Point offset = guiRecipe.getRecipePosition(recipe); + Point relMouse = new Point(mouse.x - (guiRecipe.width - 176) / 2 - offset.x, mouse.y - (guiRecipe.height - Math.min(Math.max(guiRecipe.height - 68, 166), 370)) / 2 - 10 - offset.y); + + currenttip = this.provideItemTooltip(guiRecipe, itemStack, currenttip, crecipe, relMouse); + return currenttip; + } + + public List provideItemTooltip(GuiRecipe guiRecipe, ItemStack itemStack, List currenttip, CachedBaseRecipe crecipe, Point relMouse) { + for (PositionedStack stack : crecipe.getIngredients()) { + if (stack instanceof PositionedStackAdv && ((PositionedStackAdv) stack).getRect().contains(relMouse)) { + currenttip = ((PositionedStackAdv) stack).handleTooltip(guiRecipe, currenttip); + } + } + for (PositionedStack stack : crecipe.getOtherStacks()) { + if (stack instanceof PositionedStackAdv && ((PositionedStackAdv) stack).getRect().contains(relMouse)) { + currenttip = ((PositionedStackAdv) stack).handleTooltip(guiRecipe, currenttip); + } + } + PositionedStack stack = crecipe.getResult(); + if (stack instanceof PositionedStackAdv && ((PositionedStackAdv) stack).getRect().contains(relMouse)) { + currenttip = ((PositionedStackAdv) stack).handleTooltip(guiRecipe, currenttip); + } + return currenttip; + } + + @Override + public boolean keyTyped(GuiRecipe gui, char keyChar, int keyCode, int recipe) { + if (keyCode == NEIClientConfig.getKeyBinding("gui.recipe")) { + if (this.transferFluidTank(gui, recipe, false)) { + return true; + } + } else if (keyCode == NEIClientConfig.getKeyBinding("gui.usage")) { + if (this.transferFluidTank(gui, recipe, true)) { + return true; + } + } + return super.keyTyped(gui, keyChar, keyCode, recipe); + } + + @Override + public boolean mouseClicked(GuiRecipe gui, int button, int recipe) { + if (button == 0) { + if (this.transferFluidTank(gui, recipe, false)) { + return true; + } + } else if (button == 1) { + if (this.transferFluidTank(gui, recipe, true)) { + return true; + } + } + return super.mouseClicked(gui, button, recipe); + } + + protected boolean transferFluidTank(GuiRecipe guiRecipe, int recipe, boolean usage) { + CachedBaseRecipe crecipe = (CachedBaseRecipe) this.arecipes.get(recipe); + + if (crecipe.getFluidTanks() != null) { + for (PositionedFluidTank tank : crecipe.getFluidTanks()) { + Point mouse = GuiDraw.getMousePosition(); + Point offset = guiRecipe.getRecipePosition(recipe); + Point relMouse = new Point(mouse.x - (guiRecipe.width - 176) / 2 - offset.x, mouse.y - (guiRecipe.height - Math.min(Math.max(guiRecipe.height - 68, 166), 370)) / 2 - 10 - offset.y); + + if (tank.position.contains(relMouse)) { + return tank.transfer(usage); + } + } + } + + return false; + } + + public void drawFluidTanks(int recipe) { + CachedRecipe cachedRecipe = this.arecipes.get(recipe); + if (cachedRecipe instanceof CachedBaseRecipe) { + CachedBaseRecipe crecipe = (CachedBaseRecipe) cachedRecipe; + if (crecipe.getFluidTanks() != null) { + for (PositionedFluidTank fluidTank : crecipe.getFluidTanks()) { + fluidTank.draw(); + } + } + } + } + + public abstract class CachedBaseRecipe extends CachedRecipe { + + public List getFluidTanks() { + List tanks = new ArrayList<>(); + PositionedFluidTank tank = this.getFluidTank(); + if (tank != null) { + tanks.add(tank); + } + return tanks; + } + + public PositionedFluidTank getFluidTank() { + return null; + } + + } + +} diff --git a/src/main/java/binnie/genetics/Genetics.java b/src/main/java/binnie/genetics/Genetics.java index c824c4fc..833d2210 100644 --- a/src/main/java/binnie/genetics/Genetics.java +++ b/src/main/java/binnie/genetics/Genetics.java @@ -14,6 +14,7 @@ import binnie.genetics.item.ItemDatabase; import binnie.genetics.item.ItemSerumArray; import binnie.genetics.item.ModuleItem; import binnie.genetics.machine.ModuleMachine; +import binnie.genetics.nei.IMCForNEI; import binnie.genetics.proxy.Proxy; import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.SidedProxy; @@ -60,6 +61,7 @@ public class Genetics extends AbstractMod { public void preInit(FMLPreInitializationEvent event) { addModule(new ModuleItem()); addModule(new ModuleMachine()); + IMCForNEI.IMCSender(); preInit(); } diff --git a/src/main/java/binnie/genetics/api/IIncubatorRecipe.java b/src/main/java/binnie/genetics/api/IIncubatorRecipe.java index 0dc67bb3..c5659cf4 100644 --- a/src/main/java/binnie/genetics/api/IIncubatorRecipe.java +++ b/src/main/java/binnie/genetics/api/IIncubatorRecipe.java @@ -4,11 +4,14 @@ import binnie.core.machines.MachineUtil; import net.minecraft.item.ItemStack; import net.minecraftforge.fluids.FluidStack; +import javax.annotation.Nullable; + public interface IIncubatorRecipe { boolean isInputLiquid(FluidStack liquid); boolean isInputLiquidSufficient(FluidStack liquid); + @Deprecated boolean isItemStack(ItemStack stack); void doTask(MachineUtil machine); @@ -16,4 +19,18 @@ public interface IIncubatorRecipe { float getChance(); boolean roomForOutput(MachineUtil machine); + + float getLossChance(); + + @Nullable + FluidStack getInput(); + + @Nullable + FluidStack getOutput(); + + @Nullable + ItemStack getInputStack(); + + ItemStack getExpectedOutput(); + } diff --git a/src/main/java/binnie/genetics/machine/acclimatiser/Acclimatiser.java b/src/main/java/binnie/genetics/machine/acclimatiser/Acclimatiser.java index 8978f349..4acd47a1 100644 --- a/src/main/java/binnie/genetics/machine/acclimatiser/Acclimatiser.java +++ b/src/main/java/binnie/genetics/machine/acclimatiser/Acclimatiser.java @@ -27,8 +27,8 @@ public class Acclimatiser { public static final int SLOT_TARGET = 4; public static final float ENERGY_PER_TICK = 2.0f; - protected static Map temperatureItems = new HashMap<>(); - protected static Map humidityItems = new HashMap<>(); + public static Map temperatureItems = new HashMap<>(); + public static Map humidityItems = new HashMap<>(); private static List toleranceSystems = new ArrayList<>(); diff --git a/src/main/java/binnie/genetics/machine/incubator/Incubator.java b/src/main/java/binnie/genetics/machine/incubator/Incubator.java index 24d21e6c..4006c50b 100644 --- a/src/main/java/binnie/genetics/machine/incubator/Incubator.java +++ b/src/main/java/binnie/genetics/machine/incubator/Incubator.java @@ -2,12 +2,14 @@ package binnie.genetics.machine.incubator; import binnie.Binnie; import binnie.core.BinnieCore; -import binnie.core.machines.MachineUtil; import binnie.genetics.api.IIncubatorRecipe; import binnie.genetics.item.GeneticLiquid; import binnie.genetics.item.GeneticsItems; +import forestry.api.apiculture.BeeManager; import forestry.api.apiculture.EnumBeeType; -import forestry.api.apiculture.IBee; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IIndividual; import net.minecraft.init.Items; import net.minecraft.item.ItemStack; @@ -15,88 +17,36 @@ import java.util.ArrayList; import java.util.List; public class Incubator { - public static final int[] SLOT_QUEUE = new int[]{0, 1, 2}; - public static final int[] SLOT_OUTPUT = new int[]{4, 5, 6}; - public static final int SLOT_INCUBATOR = 3; - public static final int TANK_INPUT = 0; - public static final int TANK_OUTPUT = 1; - public static final float ENERGY_PER_TICK = 2.0f; - public static final List RECIPES = new ArrayList<>(); - public static final int POWER_CAPACITY = 2000; - public static final int INPUT_TANK_CAPACITY = 2000; - public static final int OUTPU_TANK_CAPACITY = 2000; + public static final int[] SLOT_QUEUE = new int[]{0, 1, 2}; + public static final int[] SLOT_OUTPUT = new int[]{4, 5, 6}; + public static final int SLOT_INCUBATOR = 3; + public static final int TANK_INPUT = 0; + public static final int TANK_OUTPUT = 1; + public static final float ENERGY_PER_TICK = 2.0f; + public static final List RECIPES = new ArrayList<>(); + public static final int POWER_CAPACITY = 2000; + public static final int INPUT_TANK_CAPACITY = 2000; + public static final int OUTPU_TANK_CAPACITY = 2000; - public static void addRecipes() { - Incubator.RECIPES.add(new IncubatorRecipe(Binnie.Liquid.getLiquidStack("water", 25), GeneticLiquid.GrowthMedium.get(25), 0.2f) { - @Override - public boolean isItemStack(ItemStack stack) { - return GeneticsItems.GrowthMedium.get(1).isItemEqual(stack); - } - }); + public static void addRecipes() { + Incubator.RECIPES.add(new IncubatorRecipe(GeneticsItems.GrowthMedium.get(1), Binnie.Liquid.getLiquidStack("water", 25), GeneticLiquid.GrowthMedium.get(25), 0.2f)); + Incubator.RECIPES.add(new IncubatorRecipe(new ItemStack(Items.wheat), GeneticLiquid.GrowthMedium.get(25), GeneticLiquid.Bacteria.get(5), 0.2f)); + Incubator.RECIPES.add(new IncubatorRecipe(GeneticsItems.GrowthMedium.get(1), GeneticLiquid.Bacteria.get(0), GeneticLiquid.Bacteria.get(5), 0.05f)); + Incubator.RECIPES.add(new IncubatorRecipe(new ItemStack(Items.sugar), GeneticLiquid.Bacteria.get(2), null, 0.5f, 0.2f).setOutputStack(GeneticsItems.Enzyme.get(1))); + Incubator.RECIPES.add(new IncubatorRecipe(GeneticsItems.GrowthMedium.get(1), GeneticLiquid.BacteriaPoly.get(0), GeneticLiquid.BacteriaPoly.get(5), 0.05f)); + Incubator.RECIPES.add(new IncubatorRecipe(GeneticsItems.GrowthMedium.get(1), GeneticLiquid.BacteriaVector.get(0), GeneticLiquid.BacteriaVector.get(5), 0.05f)); + Incubator.RECIPES.add(new IncubatorRecipe(new ItemStack(Items.dye, 1, 15), GeneticLiquid.Bacteria.get(10), GeneticLiquid.BacteriaPoly.get(10), 0.1f)); + Incubator.RECIPES.add(new IncubatorRecipe(new ItemStack(Items.blaze_powder), GeneticLiquid.Bacteria.get(10), GeneticLiquid.BacteriaVector.get(10), 0.05f)); - Incubator.RECIPES.add(new IncubatorRecipe(GeneticLiquid.GrowthMedium.get(25), GeneticLiquid.Bacteria.get(5), 0.2f) { - @Override - public boolean isItemStack(ItemStack stack) { - return new ItemStack(Items.wheat).isItemEqual(stack); - } - }); - - Incubator.RECIPES.add(new IncubatorRecipe(GeneticLiquid.Bacteria.get(0), GeneticLiquid.Bacteria.get(5), 0.05f) { - @Override - public boolean isItemStack(ItemStack stack) { - return GeneticsItems.GrowthMedium.get(1).isItemEqual(stack); - } - }); - - Incubator.RECIPES.add(new IncubatorRecipe(GeneticLiquid.Bacteria.get(2), null, 0.5f, 0.2f) { - @Override - public boolean isItemStack(ItemStack stack) { - return stack.getItem() == Items.sugar; - } - }.setOutputStack(GeneticsItems.Enzyme.get(1))); - - Incubator.RECIPES.add(new IncubatorRecipe(GeneticLiquid.BacteriaPoly.get(0), GeneticLiquid.BacteriaPoly.get(5), 0.05f) { - @Override - public boolean isItemStack(ItemStack stack) { - return GeneticsItems.GrowthMedium.get(1).isItemEqual(stack); - } - }); - - Incubator.RECIPES.add(new IncubatorRecipe(GeneticLiquid.BacteriaVector.get(0), GeneticLiquid.BacteriaVector.get(5), 0.05f) { - @Override - public boolean isItemStack(ItemStack stack) { - return GeneticsItems.GrowthMedium.get(1).isItemEqual(stack); - } - }); - - Incubator.RECIPES.add(new IncubatorRecipe(GeneticLiquid.Bacteria.get(10), GeneticLiquid.BacteriaPoly.get(10), 0.1f) { - @Override - public boolean isItemStack(ItemStack stack) { - return new ItemStack(Items.dye, 1, 15).isItemEqual(stack); - } - }); - - Incubator.RECIPES.add(new IncubatorRecipe(GeneticLiquid.Bacteria.get(10), GeneticLiquid.BacteriaVector.get(10), 0.05f) { - @Override - public boolean isItemStack(ItemStack stack) { - return new ItemStack(Items.blaze_powder).isItemEqual(stack); - } - }); - - if (BinnieCore.isApicultureActive()) { - Incubator.RECIPES.add(new IncubatorRecipe(GeneticLiquid.GrowthMedium.get(50), null, 1.0f, 0.05f) { - @Override - public boolean isItemStack(ItemStack stack) { - return Binnie.Genetics.getBeeRoot().isMember(stack) && Binnie.Genetics.getBeeRoot().getType(stack) == EnumBeeType.LARVAE; - } - - @Override - public ItemStack getOutputStack(MachineUtil machine) { - ItemStack larvae = machine.getStack(SLOT_INCUBATOR); - IBee bee = Binnie.Genetics.getBeeRoot().getMember(larvae); - return Binnie.Genetics.getBeeRoot().getMemberStack(bee, EnumBeeType.DRONE.ordinal()); - } - }); - } - } + if (BinnieCore.isApicultureActive()) { + AlleleManager.alleleRegistry.getRegisteredAlleles().values().forEach(iAllele -> { + IAllele[] template = BeeManager.beeRoot.getTemplate(iAllele.getUID()); + if (template != null) { + IIndividual individual = BeeManager.beeRoot.templateAsIndividual(template); + ItemStack bee = BeeManager.beeRoot.getMemberStack(individual, EnumBeeType.LARVAE.ordinal()); + Incubator.RECIPES.add(new IncubatorRecipeLarvae(bee)); + } + }); + } + } } diff --git a/src/main/java/binnie/genetics/machine/incubator/IncubatorComponentLogic.java b/src/main/java/binnie/genetics/machine/incubator/IncubatorComponentLogic.java index 6b59eac6..b57e9a4e 100644 --- a/src/main/java/binnie/genetics/machine/incubator/IncubatorComponentLogic.java +++ b/src/main/java/binnie/genetics/machine/incubator/IncubatorComponentLogic.java @@ -9,142 +9,147 @@ import binnie.core.util.I18N; import binnie.genetics.api.IIncubatorRecipe; import net.minecraft.item.ItemStack; import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.oredict.OreDictionary; import java.util.Random; public class IncubatorComponentLogic extends ComponentProcessIndefinate implements IProcess { - IIncubatorRecipe recipe; - private Random rand; - private boolean roomForOutput; + IIncubatorRecipe recipe; + private final Random rand; + private boolean roomForOutput; - public IncubatorComponentLogic(Machine machine) { - super(machine, Incubator.ENERGY_PER_TICK); - recipe = null; - rand = new Random(); - roomForOutput = true; - } + public IncubatorComponentLogic(Machine machine) { + super(machine, Incubator.ENERGY_PER_TICK); + recipe = null; + rand = new Random(); + roomForOutput = true; + } - @Override - public ErrorState canWork() { - if (recipe != null) { - return super.canWork(); - } - return new ErrorState( - I18N.localise("genetics.machine.incubator.error.noRecipe.title"), - I18N.localise("genetics.machine.incubator.error.noRecipe") - ); - } + private static boolean isStackValid(ItemStack stack, IIncubatorRecipe recipe) { + return OreDictionary.itemMatches(recipe.getInputStack(), stack, false); + } - @Override - public ErrorState canProgress() { - if (recipe != null) { - if (!recipe.isInputLiquidSufficient(getUtil().getFluid(Incubator.TANK_INPUT))) { - return new ErrorState.InsufficientLiquid( - I18N.localise("genetics.machine.incubator.error.noLiquid"), - Incubator.TANK_INPUT - ); - } - if (!roomForOutput) { - return new ErrorState.TankSpace( - I18N.localise("genetics.machine.incubator.error.noRoom"), - Incubator.TANK_OUTPUT - ); - } - } - return super.canProgress(); - } + @Override + public ErrorState canWork() { + if (recipe != null) { + return super.canWork(); + } + return new ErrorState( + I18N.localise("genetics.machine.incubator.error.noRecipe.title"), + I18N.localise("genetics.machine.incubator.error.noRecipe") + ); + } - @Override - protected void onTickTask() { - if (rand.nextInt(20) == 0 && recipe != null && rand.nextFloat() < recipe.getChance()) { - recipe.doTask(getUtil()); - } - } + @Override + public ErrorState canProgress() { + if (recipe != null) { + if (!recipe.isInputLiquidSufficient(getUtil().getFluid(Incubator.TANK_INPUT))) { + return new ErrorState.InsufficientLiquid( + I18N.localise("genetics.machine.incubator.error.noLiquid"), + Incubator.TANK_INPUT + ); + } + if (!roomForOutput) { + return new ErrorState.TankSpace( + I18N.localise("genetics.machine.incubator.error.noRoom"), + Incubator.TANK_OUTPUT + ); + } + } + return super.canProgress(); + } - @Override - public boolean inProgress() { - return recipe != null; - } + @Override + protected void onTickTask() { + if (rand.nextInt(20) == 0 && recipe != null && rand.nextFloat() < recipe.getChance()) { + recipe.doTask(getUtil()); + } + } - private IIncubatorRecipe getRecipe(ItemStack stack, FluidStack liquid) { - for (IIncubatorRecipe recipe : Incubator.RECIPES) { - boolean rightLiquid = recipe.isInputLiquid(liquid); - boolean rightItem = recipe.isItemStack(stack); - if (rightLiquid && rightItem) { - return recipe; - } - } - return null; - } + @Override + public boolean inProgress() { + return recipe != null; + } - @Override - public void onInventoryUpdate() { - super.onInventoryUpdate(); - if (!getUtil().isServer()) { - return; - } + private IIncubatorRecipe getRecipe(ItemStack stack, FluidStack liquid) { + for (IIncubatorRecipe recipe : Incubator.RECIPES) { + boolean rightLiquid = recipe.isInputLiquid(liquid); + boolean rightItem = isStackValid(stack, recipe); + if (rightLiquid && rightItem) { + return recipe; + } + } + return null; + } - FluidStack liquid = getUtil().getFluid(Incubator.TANK_INPUT); - ItemStack incubator = getUtil().getStack(Incubator.SLOT_INCUBATOR); - if (recipe != null && (incubator == null || liquid == null || !recipe.isInputLiquid(liquid) || !recipe.isItemStack(incubator))) { - recipe = null; - ItemStack leftover = new TransferRequest(incubator, getInventory()) - .setTargetSlots(Incubator.SLOT_OUTPUT) - .ignoreValidation() - .transfer(true); - getUtil().setStack(Incubator.SLOT_INCUBATOR, leftover); - } + @Override + public void onInventoryUpdate() { + super.onInventoryUpdate(); + if (!getUtil().isServer()) { + return; + } - if (recipe == null) { - if (liquid == null) { - return; - } + FluidStack liquid = getUtil().getFluid(Incubator.TANK_INPUT); + ItemStack incubator = getUtil().getStack(Incubator.SLOT_INCUBATOR); + if (recipe != null && (incubator == null || liquid == null || !recipe.isInputLiquid(liquid) || !isStackValid(incubator, recipe))) { + recipe = null; + ItemStack leftover = new TransferRequest(incubator, getInventory()) + .setTargetSlots(Incubator.SLOT_OUTPUT) + .ignoreValidation() + .transfer(true); + getUtil().setStack(Incubator.SLOT_INCUBATOR, leftover); + } - if (incubator != null) { - IIncubatorRecipe recipe = getRecipe(incubator, liquid); - if (recipe != null) { - this.recipe = recipe; - return; - } - } + if (recipe == null) { + if (liquid == null) { + return; + } - IIncubatorRecipe potential = null; - int potentialSlot = 0; - for (int slot : Incubator.SLOT_QUEUE) { - ItemStack stack = getUtil().getStack(slot); - if (stack == null || potential != null) { - continue; - } + if (incubator != null) { + IIncubatorRecipe recipe = getRecipe(incubator, liquid); + if (recipe != null) { + this.recipe = recipe; + return; + } + } - for (IIncubatorRecipe recipe2 : Incubator.RECIPES) { - boolean rightLiquid = recipe2.isInputLiquid(liquid); - boolean rightItem = recipe2.isItemStack(stack); - if (rightLiquid && rightItem) { - potential = recipe2; - potentialSlot = slot; - break; - } - } - } + IIncubatorRecipe potential = null; + int potentialSlot = 0; + for (int slot : Incubator.SLOT_QUEUE) { + ItemStack stack = getUtil().getStack(slot); + if (stack == null || potential != null) { + continue; + } - if (potential != null) { - TransferRequest removal = new TransferRequest(incubator, getInventory()) - .setTargetSlots(Incubator.SLOT_OUTPUT) - .ignoreValidation(); + for (IIncubatorRecipe recipe2 : Incubator.RECIPES) { + boolean rightLiquid = recipe2.isInputLiquid(liquid); + boolean rightItem = isStackValid(stack, recipe2); + if (rightLiquid && rightItem) { + potential = recipe2; + potentialSlot = slot; + break; + } + } + } - if (removal.transfer(false) == null) { - recipe = potential; - } + if (potential != null) { + TransferRequest removal = new TransferRequest(incubator, getInventory()) + .setTargetSlots(Incubator.SLOT_OUTPUT) + .ignoreValidation(); - removal.transfer(true); - ItemStack stack2 = getUtil().getStack(potentialSlot); - getUtil().setStack(potentialSlot, null); - getUtil().setStack(Incubator.SLOT_INCUBATOR, stack2); - } - } + if (removal.transfer(false) == null) { + recipe = potential; + } - if (recipe != null) { - roomForOutput = recipe.roomForOutput(getUtil()); - } - } + removal.transfer(true); + ItemStack stack2 = getUtil().getStack(potentialSlot); + getUtil().setStack(potentialSlot, null); + getUtil().setStack(Incubator.SLOT_INCUBATOR, stack2); + } + } + + if (recipe != null) { + roomForOutput = recipe.roomForOutput(getUtil()); + } + } } diff --git a/src/main/java/binnie/genetics/machine/incubator/IncubatorRecipe.java b/src/main/java/binnie/genetics/machine/incubator/IncubatorRecipe.java index af995d2c..ddb06d4d 100644 --- a/src/main/java/binnie/genetics/machine/incubator/IncubatorRecipe.java +++ b/src/main/java/binnie/genetics/machine/incubator/IncubatorRecipe.java @@ -6,90 +6,126 @@ import binnie.genetics.api.IIncubatorRecipe; import net.minecraft.item.ItemStack; import net.minecraftforge.fluids.FluidStack; +import javax.annotation.Nullable; import java.util.Random; -public abstract class IncubatorRecipe implements IIncubatorRecipe { - protected FluidStack input; - protected FluidStack output; - protected float lossChance; - protected ItemStack outputStack; - protected float tickChance; +public class IncubatorRecipe implements IIncubatorRecipe { - public IncubatorRecipe(FluidStack input, FluidStack output, float lossChance) { - this(input, output, lossChance, 1.0f); - } + private final FluidStack input; + @Nullable + private final FluidStack output; + private final float lossChance; + private final float tickChance; + private final ItemStack inputStack; + @Nullable + private ItemStack outputStack; - public IncubatorRecipe(FluidStack input, FluidStack output, float lossChance, float chance) { - this.input = input; - this.output = output; - this.lossChance = lossChance; - tickChance = chance; - } + public IncubatorRecipe(ItemStack inputStack, final FluidStack input, @Nullable final FluidStack output, final float lossChance) { + this(inputStack, input, output, lossChance, 1.0f); + } - @Override - public float getChance() { - return tickChance; - } + public IncubatorRecipe(ItemStack inputStack, final FluidStack input, @Nullable final FluidStack output, final float lossChance, final float chance) { + this.inputStack = inputStack; + this.outputStack = null; + this.input = input; + this.output = output; + this.lossChance = lossChance; + this.tickChance = chance; + } - @Override - public boolean isInputLiquid(FluidStack liquid) { - return liquid != null && input.isFluidEqual(liquid); - } + @Override + public float getChance() { + return this.tickChance; + } - @Override - public boolean isInputLiquidSufficient(FluidStack liquid) { - return liquid != null && liquid.amount >= 500; - } + @Override + public float getLossChance() { + return lossChance; + } - @Override - public void doTask(MachineUtil machine) { - machine.drainTank(Incubator.TANK_INPUT, input.amount); - if (output != null) { - machine.fillTank(Incubator.TANK_OUTPUT, output); - } + @Override + public boolean isInputLiquid(final FluidStack fluid) { + return fluid != null && this.input.isFluidEqual(fluid); + } - outputStack = getOutputStack(machine); - if (outputStack != null) { - ItemStack output = outputStack.copy(); - TransferRequest product = new TransferRequest(output, machine.getInventory()) - .setTargetSlots(Incubator.SLOT_OUTPUT) - .ignoreValidation(); - product.transfer(true); - } + @Override + public boolean isInputLiquidSufficient(final FluidStack fluid) { + return fluid != null && fluid.amount >= this.input.amount; + } - Random rand = machine.getRandom(); - if (rand.nextFloat() < lossChance) { - machine.decreaseStack(Incubator.SLOT_INCUBATOR, 1); - } - } + @Override + public boolean isItemStack(ItemStack stack) { + return false; + } - public IncubatorRecipe setOutputStack(ItemStack stack) { - outputStack = stack; - return this; - } + @Override + public FluidStack getInput() { + return input; + } - protected ItemStack getOutputStack(MachineUtil util) { - return outputStack; - } + @Override + @Nullable + public FluidStack getOutput() { + return output; + } - @Override - public boolean roomForOutput(MachineUtil machine) { - if (output != null && !machine.isTankEmpty(Incubator.TANK_OUTPUT)) { - if (!machine.getFluid(Incubator.TANK_OUTPUT).isFluidEqual(output) || - !machine.spaceInTank(Incubator.TANK_OUTPUT, output.amount)) { - return false; - } - } + @Override + public ItemStack getInputStack() { + return inputStack; + } - ItemStack outputStack = getOutputStack(machine); - if (outputStack == null) { - return true; - } + @Override + public ItemStack getExpectedOutput() { + return outputStack; + } - ItemStack output = outputStack.copy(); - TransferRequest product = new TransferRequest(output, machine.getInventory()) - .setTargetSlots(Incubator.SLOT_OUTPUT) - .ignoreValidation(); - return product.transfer(false) == null; - } + @Override + public void doTask(final MachineUtil machine) { + machine.drainTank(Incubator.TANK_INPUT, this.input.amount); + if (this.output != null) { + machine.fillTank(Incubator.TANK_OUTPUT, this.output); + } + this.outputStack = this.getOutputStack(machine); + if (this.outputStack != null) { + final ItemStack output = this.outputStack.copy(); + final TransferRequest product = new TransferRequest(output, machine.getInventory()).setTargetSlots(Incubator.SLOT_OUTPUT).ignoreValidation(); + product.transfer(true); + } + final Random rand = machine.getRandom(); + if (rand.nextFloat() < this.lossChance) { + machine.decreaseStack(Incubator.SLOT_INCUBATOR, 1); + } + } + + public IncubatorRecipe setOutputStack(final ItemStack stack) { + this.outputStack = stack; + return this; + } + + protected ItemStack getOutputStack(final MachineUtil util) { + return getExpectedOutput(); + } + + @Override + public boolean roomForOutput(final MachineUtil machine) { + if (this.output != null && !machine.isTankEmpty(1)) { + if (!this.output.isFluidEqual(machine.getFluid(Incubator.TANK_OUTPUT))) { + return false; + } + if (!machine.spaceInTank(Incubator.TANK_OUTPUT, this.output.amount)) { + return false; + } + } + + ItemStack outputStack = getOutputStack(machine); + if (outputStack == null) { + return true; + } + + ItemStack output = outputStack.copy(); + TransferRequest product = new TransferRequest(output, machine.getInventory()) + .setTargetSlots(Incubator.SLOT_OUTPUT) + .ignoreValidation(); + return product.transfer(false) == null; + } } diff --git a/src/main/java/binnie/genetics/machine/incubator/IncubatorRecipeLarvae.java b/src/main/java/binnie/genetics/machine/incubator/IncubatorRecipeLarvae.java new file mode 100644 index 00000000..50601325 --- /dev/null +++ b/src/main/java/binnie/genetics/machine/incubator/IncubatorRecipeLarvae.java @@ -0,0 +1,29 @@ +package binnie.genetics.machine.incubator; + +import binnie.core.machines.MachineUtil; +import binnie.genetics.item.GeneticLiquid; +import forestry.api.apiculture.BeeManager; +import forestry.api.apiculture.EnumBeeType; +import forestry.api.apiculture.IBee; +import net.minecraft.item.ItemStack; + +public class IncubatorRecipeLarvae extends IncubatorRecipe { + public IncubatorRecipeLarvae(ItemStack beeLarvaeWildcard) { + super(beeLarvaeWildcard, GeneticLiquid.GrowthMedium.get(50), null, 1.0f, 0.05f); + } + + @Override + public ItemStack getOutputStack(final MachineUtil machine) { + final ItemStack larvae = machine.getStack(Incubator.SLOT_INCUBATOR); + final IBee bee = BeeManager.beeRoot.getMember(larvae); + if (bee == null) { + return null; + } + return BeeManager.beeRoot.getMemberStack(bee, EnumBeeType.DRONE.ordinal()); + } + + @Override + public ItemStack getExpectedOutput() { + return BeeManager.beeRoot.getMemberStack(BeeManager.beeRoot.getMember(this.getInputStack()), EnumBeeType.DRONE.ordinal()); + } +} diff --git a/src/main/java/binnie/genetics/nei/AcclimatiserRecipeHandler.java b/src/main/java/binnie/genetics/nei/AcclimatiserRecipeHandler.java new file mode 100644 index 00000000..0471934d --- /dev/null +++ b/src/main/java/binnie/genetics/nei/AcclimatiserRecipeHandler.java @@ -0,0 +1,184 @@ +package binnie.genetics.nei; + +import binnie.botany.Botany; +import binnie.core.BinnieCore; +import binnie.core.Mods; +import binnie.core.nei.PositionedStackAdv; +import binnie.core.nei.RecipeHandlerBase; +import binnie.genetics.machine.acclimatiser.Acclimatiser; +import binnie.genetics.machine.acclimatiser.ToleranceType; +import codechicken.lib.gui.GuiDraw; +import codechicken.nei.NEIServerUtils; +import codechicken.nei.PositionedStack; +import net.minecraft.item.ItemStack; +import net.minecraft.util.StatCollector; +import net.minecraftforge.oredict.OreDictionary; + +import java.util.ArrayList; +import java.util.List; + +public class AcclimatiserRecipeHandler extends RecipeHandlerBase { + + private static final List recipes = new ArrayList<>(); + + @Override + public void prepare() { + Acclimatiser.temperatureItems.forEach((resource, effect) -> { + List targets = new ArrayList<>(); + if (BinnieCore.isApicultureActive()) { + targets.add(Mods.forestry.stack("beeDroneGE", 1, OreDictionary.WILDCARD_VALUE)); + targets.add(Mods.forestry.stack("beePrincessGE", 1, OreDictionary.WILDCARD_VALUE)); + targets.add(Mods.forestry.stack("beeQueenGE", 1, OreDictionary.WILDCARD_VALUE)); + targets.add(Mods.forestry.stack("beeLarvaeGE", 1, OreDictionary.WILDCARD_VALUE)); + } + if (BinnieCore.isLepidopteryActive()) { + targets.add(Mods.forestry.stack("butterflyGE", 1, OreDictionary.WILDCARD_VALUE)); + targets.add(Mods.forestry.stack("caterpillarGE", 1, OreDictionary.WILDCARD_VALUE)); + targets.add(Mods.forestry.stack("serumGE", 1, OreDictionary.WILDCARD_VALUE)); + } + if (BinnieCore.isBotanyActive()) { + targets.add(new ItemStack(Botany.flowerItem, 1, OreDictionary.WILDCARD_VALUE)); + targets.add(new ItemStack(Botany.seed, 1, OreDictionary.WILDCARD_VALUE)); + targets.add(new ItemStack(Botany.pollen, 1, OreDictionary.WILDCARD_VALUE)); + } + recipes.add(new AcclimatiserRecipe(targets, resource, effect, ToleranceType.Temperature)); + }); + Acclimatiser.humidityItems.forEach((resource, effect) -> { + List targets = new ArrayList<>(); + if (BinnieCore.isApicultureActive()) { + targets.add(Mods.forestry.stack("beeDroneGE", 1, OreDictionary.WILDCARD_VALUE)); + targets.add(Mods.forestry.stack("beePrincessGE", 1, OreDictionary.WILDCARD_VALUE)); + targets.add(Mods.forestry.stack("beeQueenGE", 1, OreDictionary.WILDCARD_VALUE)); + targets.add(Mods.forestry.stack("beeLarvaeGE", 1, OreDictionary.WILDCARD_VALUE)); + } + if (BinnieCore.isLepidopteryActive()) { + targets.add(Mods.forestry.stack("butterflyGE", 1, OreDictionary.WILDCARD_VALUE)); + targets.add(Mods.forestry.stack("caterpillarGE", 1, OreDictionary.WILDCARD_VALUE)); + targets.add(Mods.forestry.stack("serumGE", 1, OreDictionary.WILDCARD_VALUE)); + } + if (BinnieCore.isBotanyActive()) { + targets.add(new ItemStack(Botany.flowerItem, 1, OreDictionary.WILDCARD_VALUE)); + targets.add(new ItemStack(Botany.seed, 1, OreDictionary.WILDCARD_VALUE)); + targets.add(new ItemStack(Botany.pollen, 1, OreDictionary.WILDCARD_VALUE)); + } + recipes.add(new AcclimatiserRecipe(targets, resource, effect, ToleranceType.Humidity)); + }); + + } + + @Override + public String getOverlayIdentifier() { + return "genetics.acclimatiser"; + } + + @Override + public String getGuiTexture() { + return "genetics:textures/gui/nei/acclimatiser.png"; + } + + @Override + public String getRecipeName() { + return StatCollector.translateToLocal("genetics.machine.labMachine.acclimatiser"); + } + + @Override + public void loadTransferRects() { + this.addTransferRect(75, 21, 18, 7); + } + + @Override + public void drawBackground(int recipe) { + changeToGuiTexture(); + GuiDraw.drawTexturedModalRect(0, 0, 5, 11, 166, 76); + } + + @Override + public void loadAllRecipes() { + for (AcclimatiserRecipe recipe : recipes) { + this.arecipes.add(new CachedAcclimatiserRecipe(recipe)); + } + } + + @Override + public void loadUsageRecipes(ItemStack ingredient) { + for (AcclimatiserRecipe recipe : recipes) { + if (NEIServerUtils.areStacksSameTypeCrafting(recipe.getResource(), ingredient)) { + this.arecipes.add(new CachedAcclimatiserRecipe(recipe)); + } else { + for (ItemStack itemStack : recipe.getTarget()) { + if (NEIServerUtils.areStacksSameTypeCrafting(itemStack, ingredient)) { + this.arecipes.add(new CachedAcclimatiserRecipe(recipe)); + break; + } + } + } + } + } + + private static class AcclimatiserRecipe { + private final ItemStack[] target; + private final ItemStack resource; + private final float effect; + private final ToleranceType type; + + public AcclimatiserRecipe(Object target, ItemStack resource, float effect, ToleranceType type) { + this.target = NEIServerUtils.extractRecipeItems(target); + this.resource = resource; + this.effect = effect; + this.type = type; + } + + public ItemStack getResource() { + return this.resource; + } + + public ItemStack[] getTarget() { + return this.target; + } + + public float getEffect() { + return this.effect; + } + + public ToleranceType getType() { + return this.type; + } + + } + + public class CachedAcclimatiserRecipe extends CachedBaseRecipe { + + public List target = new ArrayList<>(); + public PositionedStack resource; + public float effect; + public ToleranceType type; + public List ingredients = new ArrayList<>(); + + public CachedAcclimatiserRecipe(AcclimatiserRecipe recipe) { + if (recipe.getTarget() != null) { + for (int i = 0; i < recipe.getTarget().length; i++) { + target.add(new PositionedStack(recipe.getTarget()[i], 31 + 18 * (i > 5 ? i % 6 : i), 29 + 18 * (i / 6))); + } + this.resource = new PositionedStackAdv(recipe.getResource(), 76, 2) + .addToTooltip(StatCollector.translateToLocal("genetics.nei.tip." + (recipe.getType().equals(ToleranceType.Temperature) ? "temperature" : "humidity"))) + .addToTooltip(StatCollector.translateToLocalFormatted("genetics.nei.tip.effect", recipe.getEffect())); + this.effect = recipe.getEffect(); + this.type = recipe.getType(); + + this.ingredients.addAll(this.target); + this.ingredients.add(this.resource); + } + } + + @Override + public List getIngredients() { + return getCycledIngredients(cycleticks / 40, this.ingredients); + } + + @Override + public PositionedStack getResult() { + return null; + } + } + +} diff --git a/src/main/java/binnie/genetics/nei/AnalyserRecipeHandler.java b/src/main/java/binnie/genetics/nei/AnalyserRecipeHandler.java new file mode 100644 index 00000000..c87dbc00 --- /dev/null +++ b/src/main/java/binnie/genetics/nei/AnalyserRecipeHandler.java @@ -0,0 +1,169 @@ +package binnie.genetics.nei; + +import binnie.botany.Botany; +import binnie.core.BinnieCore; +import binnie.core.Mods; +import binnie.core.nei.RecipeHandlerBase; +import binnie.genetics.Genetics; +import binnie.genetics.item.GeneticsItems; +import binnie.genetics.item.ItemSequence; +import codechicken.lib.gui.GuiDraw; +import codechicken.nei.ItemList; +import codechicken.nei.NEIServerUtils; +import codechicken.nei.PositionedStack; +import net.minecraft.item.ItemStack; +import net.minecraft.util.StatCollector; +import net.minecraftforge.oredict.OreDictionary; + +import java.util.ArrayList; +import java.util.List; + +public class AnalyserRecipeHandler extends RecipeHandlerBase { + + private static final List recipes = new ArrayList<>(); + + @Override + public void prepare() { + recipes.add(new AnalyserRecipe(new ItemStack(Genetics.itemSequencer, 1, OreDictionary.WILDCARD_VALUE))); + + if (BinnieCore.isApicultureActive()) { + recipes.add(new AnalyserRecipe(Mods.forestry.stack("beeDroneGE", 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new AnalyserRecipe(Mods.forestry.stack("beePrincessGE", 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new AnalyserRecipe(Mods.forestry.stack("beeQueenGE", 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new AnalyserRecipe(Mods.forestry.stack("beeLarvaeGE", 1, OreDictionary.WILDCARD_VALUE))); + } + if (BinnieCore.isArboricultureActive()) { + recipes.add(new AnalyserRecipe(Mods.forestry.stack("sapling", 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new AnalyserRecipe(Mods.forestry.stack("pollenFertile", 1, OreDictionary.WILDCARD_VALUE))); + } + if (BinnieCore.isLepidopteryActive()) { + recipes.add(new AnalyserRecipe(Mods.forestry.stack("butterflyGE", 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new AnalyserRecipe(Mods.forestry.stack("caterpillarGE", 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new AnalyserRecipe(Mods.forestry.stack("serumGE", 1, OreDictionary.WILDCARD_VALUE))); + } + if (BinnieCore.isBotanyActive()) { + recipes.add(new AnalyserRecipe(new ItemStack(Botany.flowerItem, 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new AnalyserRecipe(new ItemStack(Botany.seed, 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new AnalyserRecipe(new ItemStack(Botany.pollen, 1, OreDictionary.WILDCARD_VALUE))); + } + } + + @Override + public String getOverlayIdentifier() { + return "genetics.analyser"; + } + + @Override + public String getGuiTexture() { + return "genetics:textures/gui/nei/analyser.png"; + } + + @Override + public String getRecipeName() { + return StatCollector.translateToLocal("genetics.machine.labMachine.analyser"); + } + + @Override + public void loadTransferRects() { + this.addTransferRect(50, 13, 66, 11); + this.addTransferRect(50, 42, 66, 11); + this.addTransferRect(50, 24, 24, 18); + this.addTransferRect(92, 24, 24, 18); + } + + @Override + public void drawBackground(int recipe) { + changeToGuiTexture(); + GuiDraw.drawTexturedModalRect(0, 0, 5, 11, 166, 74); + } + + @Override + public void drawExtras(int recipe) { + this.drawProgressBar(50, 13, 176, 0, 66, 40, 40, 0); + } + + @Override + public void loadAllRecipes() { + for (AnalyserRecipe recipe : recipes) { + this.arecipes.add(new CachedAnalyser(recipe)); + } + } + + @Override + public void loadUsageRecipes(ItemStack ingredient) { + if (NEIServerUtils.areStacksSameTypeCrafting(GeneticsItems.DNADye.get(0), ingredient)) { + this.loadAllRecipes(); + } else { + for (AnalyserRecipe recipe : recipes) { + if (NEIServerUtils.areStacksSameTypeCrafting(recipe.getAnalysable(), ingredient)) { + this.arecipes.add(new CachedAnalyser(recipe)); + } + } + } + } + + private static class AnalyserRecipe { + private final ItemStack analysable; + + public AnalyserRecipe(ItemStack analysable) { + this.analysable = analysable; + } + + public ItemStack getDNADye() { + return GeneticsItems.DNADye.get(1); + } + + public ItemStack getAnalysable() { + return this.analysable; + } + + } + + public class CachedAnalyser extends CachedBaseRecipe { + + public PositionedStack analysable; + public PositionedStack dnaDye; + public List ingredients = new ArrayList<>(); + + public CachedAnalyser(AnalyserRecipe recipe) { + if (recipe.getAnalysable() != null) { + List analysableList = new ArrayList<>(); + + if (recipe.getAnalysable().getItem() instanceof ItemSequence) { + for (ItemStack seq : ItemList.itemMap.get(Genetics.itemSequencer)) { + for (int i = Genetics.itemSequencer.getMaxDamage(); i >= 0; i--) { + ItemStack temp = seq.copy(); + temp.setItemDamage(i); + analysableList.add(temp); + } + } + } else { + for (ItemStack analysable : ItemList.itemMap.get(recipe.getAnalysable().getItem())) { + if (analysable.getTagCompound() != null) { + analysableList.add(analysable.copy()); + } + } + } + + this.analysable = new PositionedStack(analysableList, 75, 25); + this.dnaDye = new PositionedStack(recipe.getDNADye(), 75, 56); + + this.ingredients.add(this.analysable); + this.ingredients.add(this.dnaDye); + } + } + + @Override + public List getIngredients() { + this.analysable.setPermutationToRender(cycleticks / 40 % this.analysable.items.length); + return this.ingredients; + } + + @Override + public PositionedStack getResult() { + return null; + } + + } + +} diff --git a/src/main/java/binnie/genetics/nei/DatabaseRecipeHandler.java b/src/main/java/binnie/genetics/nei/DatabaseRecipeHandler.java new file mode 100644 index 00000000..a8754ef6 --- /dev/null +++ b/src/main/java/binnie/genetics/nei/DatabaseRecipeHandler.java @@ -0,0 +1,142 @@ +package binnie.genetics.nei; + +import binnie.core.nei.RecipeHandlerBase; +import binnie.genetics.Genetics; +import binnie.genetics.item.GeneticsItems; +import binnie.genetics.item.ItemSerumArray; +import codechicken.lib.gui.GuiDraw; +import codechicken.nei.ItemList; +import codechicken.nei.NEIServerUtils; +import codechicken.nei.PositionedStack; +import net.minecraft.item.ItemStack; +import net.minecraft.util.StatCollector; +import net.minecraftforge.oredict.OreDictionary; + +import java.util.ArrayList; +import java.util.List; + +public class DatabaseRecipeHandler extends RecipeHandlerBase { + + private static final List recipes = new ArrayList<>(); + + @Override + public void prepare() { + recipes.add(new DatabaseRecipe(new ItemStack(Genetics.itemSerum, 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new DatabaseRecipe(new ItemStack(Genetics.itemSerumArray, 1, OreDictionary.WILDCARD_VALUE))); + } + + @Override + public String getOverlayIdentifier() { + return "genetics.database"; + } + + @Override + public String getGuiTexture() { + return "genetics:textures/gui/nei/database.png"; + } + + @Override + public String getRecipeName() { + return StatCollector.translateToLocal("genetics.item.database.0.name"); + } + + @Override + public void loadTransferRects() { + this.addTransferRect(75, 7, 24, 17); + } + + @Override + public void drawBackground(int recipe) { + changeToGuiTexture(); + GuiDraw.drawTexturedModalRect(0, 0, 5, 11, 166, 74); + } + + @Override + public void drawExtras(int recipe) { + this.drawProgressBar(75, 7, 176, 0, 24, 17, 40, 0); + + List desc = GuiDraw.fontRenderer.listFormattedStringToWidth(StatCollector.translateToLocalFormatted("genetics.nei.tip.databaseDesc"), 140); + for (int i = 0; i < desc.size(); i++) { + GuiDraw.drawStringC(desc.get(i), 88, 44 + 12 * (i - 1), 0xFFFFFF); + } + } + + @Override + public void loadAllRecipes() { + for (DatabaseRecipe recipe : recipes) { + this.arecipes.add(new CachedDatabaseRecipe(recipe)); + } + } + + @Override + public void loadCraftingRecipes(ItemStack result) { + for (DatabaseRecipe recipe : recipes) { + if (NEIServerUtils.areStacksSameTypeCrafting(recipe.getSerum(), result)) { + this.arecipes.add(new CachedDatabaseRecipe(recipe)); + } + } + } + + @Override + public void loadUsageRecipes(ItemStack ingredient) { + for (DatabaseRecipe recipe : recipes) { + if (NEIServerUtils.areStacksSameTypeCrafting(recipe.getEmptySerum(), ingredient)) { + this.arecipes.add(new CachedDatabaseRecipe(recipe)); + } + } + } + + private static class DatabaseRecipe { + + private final ItemStack serum; + + public DatabaseRecipe(ItemStack serum) { + this.serum = serum; + } + + public ItemStack getSerum() { + return this.serum; + } + + public ItemStack getEmptySerum() { + return this.serum.getItem() instanceof ItemSerumArray ? GeneticsItems.EmptyGenome.get(1) : GeneticsItems.EmptySerum.get(1); + } + + } + + public class CachedDatabaseRecipe extends CachedBaseRecipe { + + public PositionedStack serum; + public PositionedStack emptySerum; + + public CachedDatabaseRecipe(DatabaseRecipe recipe) { + if (recipe.getSerum() != null) { + List serums = new ArrayList<>(); + + for (ItemStack serumStack : ItemList.itemMap.get(recipe.getSerum().getItem())) { + if (serumStack.getTagCompound() != null) { + ItemStack temp = serumStack.copy(); + temp.setItemDamage(temp.getMaxDamage()); + serums.add(temp); + } + } + + this.emptySerum = new PositionedStack(recipe.getEmptySerum(), 53, 7); + this.serum = new PositionedStack(serums, 105, 7); + } + } + + @Override + public PositionedStack getIngredient() { + this.serum.setPermutationToRender(cycleticks / 40 % this.serum.items.length); + return this.serum; + } + + @Override + public PositionedStack getResult() { + return this.emptySerum; + } + + } + +} diff --git a/src/main/java/binnie/genetics/nei/GenepoolRecipeHandler.java b/src/main/java/binnie/genetics/nei/GenepoolRecipeHandler.java new file mode 100644 index 00000000..35466472 --- /dev/null +++ b/src/main/java/binnie/genetics/nei/GenepoolRecipeHandler.java @@ -0,0 +1,193 @@ +package binnie.genetics.nei; + +import binnie.Binnie; +import binnie.botany.Botany; +import binnie.core.BinnieCore; +import binnie.core.Mods; +import binnie.core.nei.NEIUtils; +import binnie.core.nei.PositionedFluidTank; +import binnie.core.nei.RecipeHandlerBase; +import binnie.genetics.item.GeneticLiquid; +import binnie.genetics.item.GeneticsItems; +import codechicken.lib.gui.GuiDraw; +import codechicken.nei.NEIServerUtils; +import codechicken.nei.PositionedStack; +import forestry.api.apiculture.EnumBeeType; +import net.minecraft.item.ItemStack; +import net.minecraft.util.StatCollector; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.oredict.OreDictionary; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +public class GenepoolRecipeHandler extends RecipeHandlerBase { + + private static final List recipes = new ArrayList<>(); + + @Override + public void prepare() { + if (BinnieCore.isApicultureActive()) { + recipes.add(new GenepoolRecipe(Mods.forestry.stack("beeDroneGE", 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new GenepoolRecipe(Mods.forestry.stack("beePrincessGE", 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new GenepoolRecipe(Mods.forestry.stack("beeQueenGE", 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new GenepoolRecipe(Mods.forestry.stack("beeLarvaeGE", 1, OreDictionary.WILDCARD_VALUE))); + } + if (BinnieCore.isArboricultureActive()) { + recipes.add(new GenepoolRecipe(Mods.forestry.stack("sapling", 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new GenepoolRecipe(Mods.forestry.stack("pollenFertile", 1, OreDictionary.WILDCARD_VALUE))); + } + if (BinnieCore.isLepidopteryActive()) { + recipes.add(new GenepoolRecipe(Mods.forestry.stack("butterflyGE", 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new GenepoolRecipe(Mods.forestry.stack("caterpillarGE", 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new GenepoolRecipe(Mods.forestry.stack("serumGE", 1, OreDictionary.WILDCARD_VALUE))); + } + if (BinnieCore.isBotanyActive()) { + recipes.add(new GenepoolRecipe(new ItemStack(Botany.flowerItem, 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new GenepoolRecipe(new ItemStack(Botany.seed, 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new GenepoolRecipe(new ItemStack(Botany.pollen, 1, OreDictionary.WILDCARD_VALUE))); + } + } + + @Override + public String getOverlayIdentifier() { + return "genetics.genepool"; + } + + @Override + public String getGuiTexture() { + return "genetics:textures/gui/nei/genepool.png"; + } + + @Override + public String getRecipeName() { + return StatCollector.translateToLocal("genetics.machine.labMachine.genepool"); + } + + @Override + public void loadTransferRects() { + this.addTransferRect(75, 38, 24, 17); + } + + @Override + public void drawBackground(int recipe) { + changeToGuiTexture(); + GuiDraw.drawTexturedModalRect(0, 0, 5, 11, 166, 74); + } + + @Override + public void drawExtras(int recipe) { + this.drawProgressBar(75, 38, 176, 0, 24, 17, 40, 0); + } + + @Override + public void loadAllRecipes() { + for (GenepoolRecipe recipe : recipes) { + this.arecipes.add(new CachedGenepoolRecipe(recipe)); + } + } + + @Override + public void loadCraftingRecipes(FluidStack result) { + if (NEIUtils.areFluidsSameType(GeneticLiquid.RawDNA.get(0), result)) { + this.loadAllRecipes(); + } + } + + @Override + public void loadUsageRecipes(ItemStack ingredient) { + if (NEIServerUtils.areStacksSameTypeCrafting(GeneticsItems.Enzyme.get(1), ingredient)) { + this.loadAllRecipes(); + } else { + for (GenepoolRecipe recipe : recipes) { + if (NEIServerUtils.areStacksSameTypeCrafting(recipe.getInput(), ingredient)) { + this.arecipes.add(new CachedGenepoolRecipe(recipe)); + } + } + } + } + + @Override + public void loadUsageRecipes(FluidStack ingredient) { + if (NEIUtils.areFluidsSameType(Binnie.Liquid.getLiquidStack("bioethanol", 0), ingredient)) { + this.loadAllRecipes(); + } + } + + private static class GenepoolRecipe { + private final ItemStack inputStack; + + public GenepoolRecipe(ItemStack inputStack) { + this.inputStack = inputStack; + } + + public FluidStack getRawDNA() { + int amount; + EnumBeeType type = Binnie.Genetics.getBeeRoot().getType(this.inputStack); + + switch (type) { + case QUEEN: + amount = 50; + break; + case PRINCESS: + amount = 30; + break; + default: + amount = 10; + break; + } + + return GeneticLiquid.RawDNA.get(amount); + } + + public ItemStack getEnzyme() { + return GeneticsItems.Enzyme.get(1); + } + + public FluidStack getEthanol() { + return Binnie.Liquid.getLiquidStack("bioethanol", (int) (getRawDNA().amount * 1.2)); + } + + public ItemStack getInput() { + return this.inputStack; + } + + } + + public class CachedGenepoolRecipe extends CachedBaseRecipe { + public List tanks = new ArrayList<>(); + public List ingredients = new ArrayList<>(); + public PositionedStack input; + public PositionedStack enzyme; + + public CachedGenepoolRecipe(GenepoolRecipe recipe) { + if (recipe.getInput() != null) { + this.tanks.add(new PositionedFluidTank(recipe.getEthanol(), 100, new Rectangle(38, 6, 16, 58))); + this.tanks.add(new PositionedFluidTank(recipe.getRawDNA(), 100, new Rectangle(119, 6, 16, 58))); + this.enzyme = new PositionedStack(recipe.getEnzyme(), 58, 6); + this.input = new PositionedStack(recipe.getInput(), 78, 6); + this.ingredients.add(this.enzyme); + this.ingredients.add(this.input); + } + } + + + @Override + public List getIngredients() { + return getCycledIngredients(cycleticks / 40, this.ingredients); + } + + @Override + public List getFluidTanks() { + return this.tanks; + } + + @Override + public PositionedStack getResult() { + return null; + } + + } + +} diff --git a/src/main/java/binnie/genetics/nei/IMCForNEI.java b/src/main/java/binnie/genetics/nei/IMCForNEI.java new file mode 100644 index 00000000..8d5fd510 --- /dev/null +++ b/src/main/java/binnie/genetics/nei/IMCForNEI.java @@ -0,0 +1,58 @@ +package binnie.genetics.nei; + +import cpw.mods.fml.common.event.FMLInterModComms; +import net.minecraft.nbt.NBTTagCompound; + +public class IMCForNEI { + public static void IMCSender() { + sendHandler("genetics.isolator", "Genetics:machine:0"); + sendHandler("genetics.sequencer", "Genetics:machine:1"); + sendHandler("genetics.polymeriser", "Genetics:machine:2"); + sendHandler("genetics.inoculator", "Genetics:machine:3"); + sendHandler("genetics.analyser", "Genetics:labMachine:1"); + sendHandler("genetics.incubator", "Genetics:labMachine:2"); + sendHandler("genetics.genepool", "Genetics:labMachine:3"); + sendHandler("genetics.acclimatiser", "Genetics:labMachine:4"); + sendHandler("genetics.splicer", "Genetics:advMachine:0"); + sendHandler("genetics.database", "Genetics:database:0"); + + sendCatalyst("genetics.isolator", "Genetics:machine:0"); + sendCatalyst("genetics.sequencer", "Genetics:machine:1"); + sendCatalyst("genetics.polymeriser", "Genetics:machine:2"); + sendCatalyst("genetics.inoculator", "Genetics:machine:3"); + sendCatalyst("genetics.database", "Genetics:database:0"); + sendCatalyst("genetics.database", "Genetics:database:1"); + sendCatalyst("genetics.database", "Genetics:labMachine:0"); + sendCatalyst("genetics.analyser", "Genetics:labMachine:1"); + sendCatalyst("genetics.incubator", "Genetics:labMachine:2"); + sendCatalyst("genetics.genepool", "Genetics:labMachine:3"); + sendCatalyst("genetics.acclimatiser", "Genetics:labMachine:4"); + sendCatalyst("genetics.splicer", "Genetics:advMachine:0"); + } + + private static void sendHandler(String aName, String aBlock) { + NBTTagCompound aNBT = new NBTTagCompound(); + aNBT.setString("handler", aName); + aNBT.setString("modName", "Genetics"); + aNBT.setString("modId", "Genetics"); + aNBT.setBoolean("modRequired", true); + aNBT.setString("itemName", aBlock); + aNBT.setInteger("handlerHeight", 76); + aNBT.setInteger("handlerWidth", 166); + aNBT.setInteger("maxRecipesPerPage", 4); + aNBT.setInteger("yShift", 6); + FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT); + } + + private static void sendCatalyst(String aName, String aStack, int aPriority) { + NBTTagCompound aNBT = new NBTTagCompound(); + aNBT.setString("handlerID", aName); + aNBT.setString("itemName", aStack); + aNBT.setInteger("priority", aPriority); + FMLInterModComms.sendMessage("NotEnoughItems", "registerCatalystInfo", aNBT); + } + + private static void sendCatalyst(String aName, String aStack) { + sendCatalyst(aName, aStack, 0); + } +} \ No newline at end of file diff --git a/src/main/java/binnie/genetics/nei/IncubatorRecipeHandler.java b/src/main/java/binnie/genetics/nei/IncubatorRecipeHandler.java new file mode 100644 index 00000000..55002ef9 --- /dev/null +++ b/src/main/java/binnie/genetics/nei/IncubatorRecipeHandler.java @@ -0,0 +1,168 @@ +package binnie.genetics.nei; + +import binnie.core.nei.NEIUtils; +import binnie.core.nei.PositionedFluidTank; +import binnie.core.nei.RecipeHandlerBase; +import binnie.genetics.api.IIncubatorRecipe; +import binnie.genetics.machine.incubator.Incubator; +import codechicken.lib.gui.GuiDraw; +import codechicken.nei.NEIServerUtils; +import codechicken.nei.PositionedStack; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraftforge.fluids.FluidStack; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +public class IncubatorRecipeHandler extends RecipeHandlerBase { + + @Override + public String getOverlayIdentifier() { + return "genetics.incubator"; + } + + @Override + public String getGuiTexture() { + return "genetics:textures/gui/nei/incubator.png"; + } + + @Override + public String getRecipeName() { + return StatCollector.translateToLocal("genetics.machine.labMachine.incubator"); + } + + @Override + public void loadTransferRects() { + this.addTransferRect(75, 27, 24, 17); + } + + @Override + public void drawBackground(int recipe) { + changeToGuiTexture(); + GuiDraw.drawTexturedModalRect(0, 0, 5, 11, 166, 76); + } + + @Override + public void drawExtras(int recipe) { + this.drawProgressBar(75, 27, 176, 0, 24, 17, 40, 0); + GuiDraw.drawStringC(StatCollector.translateToLocal("genetics.nei.tip.loss"), 62, 5, 0xFFFFFF); + GuiDraw.drawStringC(((CachedIncubatorRecipe) arecipes.get(recipe)).lossChance, 62, 15, 0xFFFFFF); + } + + @Override + public void loadAllRecipes() { + for (IIncubatorRecipe recipe : Incubator.RECIPES) { + this.arecipes.add(new CachedIncubatorRecipe(recipe)); + } + } + + @Override + public void loadCraftingRecipes(ItemStack result) { + for (IIncubatorRecipe recipe : Incubator.RECIPES) { + if (NEIServerUtils.areStacksSameTypeCrafting(recipe.getExpectedOutput(), result)) { + this.arecipes.add(new CachedIncubatorRecipe(recipe)); + } + } + } + + @Override + public void loadCraftingRecipes(FluidStack result) { + for (IIncubatorRecipe recipe : Incubator.RECIPES) { + if (NEIUtils.areFluidsSameType(recipe.getOutput(), result)) { + this.arecipes.add(new CachedIncubatorRecipe(recipe)); + } + } + } + + @Override + public void loadUsageRecipes(ItemStack ingredient) { + for (IIncubatorRecipe recipe : Incubator.RECIPES) { + if (NEIServerUtils.areStacksSameTypeCrafting(recipe.getInputStack(), ingredient)) { + this.arecipes.add(new CachedIncubatorRecipe(recipe)); + } + } + + } + + @Override + public void loadUsageRecipes(FluidStack ingredient) { + for (IIncubatorRecipe recipe : Incubator.RECIPES) { + if (NEIUtils.areFluidsSameType(recipe.getInput(), ingredient)) { + this.arecipes.add(new CachedIncubatorRecipe(recipe)); + } + } + } + + public class CachedIncubatorRecipe extends CachedBaseRecipe { + public List tanks = new ArrayList<>(); + public PositionedStack input; + public PositionedStack output; + public String lossChance; + public String tickChance; + public boolean consume = true; + + public CachedIncubatorRecipe(IIncubatorRecipe recipe) { + if (recipe.getInput() != null) { + FluidStack fluidStack = recipe.getInput(); + + if (fluidStack.amount == 0) { + fluidStack.amount = 1; + consume = false; + } + + boolean finalConsume = consume; + PositionedFluidTank tank = new PositionedFluidTank(fluidStack, 100, new Rectangle(28, 6, 16, 58)) { + @Override + public List handleTooltip(List currenttip) { + if (this.tank != null && this.tank.getFluid() != null && this.tank.getFluid().getFluid() != null && this.tank.getFluid().amount > 0) { + currenttip.add(this.tank.getFluid().getLocalizedName()); + if (this.showAmount) { + currenttip.add(EnumChatFormatting.GRAY.toString() + this.tank.getFluid().amount + (this.perTick ? " mB/t" : " mB")); + } + if (!finalConsume) { + currenttip.add(StatCollector.translateToLocal("genetics.nei.tip.noConsume")); + } + } + return currenttip; + } + }; + this.tanks.add(tank); + } + + if (recipe.getOutput() != null) { + this.tanks.add(new PositionedFluidTank(recipe.getOutput(), 100, new Rectangle(130, 6, 16, 58))); + } + + if (recipe.getInputStack() != null) { + this.input = new PositionedStack(recipe.getInputStack(), 53, 27); + } + + if (recipe.getExpectedOutput() != null) { + this.output = new PositionedStack(recipe.getExpectedOutput(), 105, 27); + } + + this.lossChance = recipe.getLossChance() * 100 + "%"; + + } + + @Override + public List getFluidTanks() { + return this.tanks; + } + + @Override + public PositionedStack getIngredient() { + return this.input; + } + + @Override + public PositionedStack getResult() { + return this.output; + } + + } + +} diff --git a/src/main/java/binnie/genetics/nei/InoculatorRecipeHandler.java b/src/main/java/binnie/genetics/nei/InoculatorRecipeHandler.java new file mode 100644 index 00000000..3a7c754a --- /dev/null +++ b/src/main/java/binnie/genetics/nei/InoculatorRecipeHandler.java @@ -0,0 +1,187 @@ +package binnie.genetics.nei; + +import binnie.botany.Botany; +import binnie.core.BinnieCore; +import binnie.core.Mods; +import binnie.core.nei.NEIUtils; +import binnie.core.nei.PositionedFluidTank; +import binnie.core.nei.RecipeHandlerBase; +import binnie.genetics.Genetics; +import binnie.genetics.api.IItemSerum; +import binnie.genetics.item.GeneticLiquid; +import codechicken.lib.gui.GuiDraw; +import codechicken.nei.ItemList; +import codechicken.nei.NEIServerUtils; +import codechicken.nei.PositionedStack; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.ISpeciesRoot; +import net.minecraft.item.ItemStack; +import net.minecraft.util.StatCollector; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.oredict.OreDictionary; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +public class InoculatorRecipeHandler extends RecipeHandlerBase { + + private static final List recipes = new ArrayList<>(); + + private void createInoculatorRecipeForNEI(ItemStack dnaManipulable) { + recipes.add(new InoculatorRecipe(dnaManipulable, new ItemStack(Genetics.itemSerum, 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new InoculatorRecipe(dnaManipulable, new ItemStack(Genetics.itemSerumArray, 1, OreDictionary.WILDCARD_VALUE))); + } + + @Override + public void prepare() { + if (BinnieCore.isApicultureActive()) + createInoculatorRecipeForNEI(Mods.forestry.stack("beeLarvaeGE", 1, OreDictionary.WILDCARD_VALUE)); + if (BinnieCore.isArboricultureActive()) + createInoculatorRecipeForNEI(Mods.forestry.stack("pollenFertile", 1, OreDictionary.WILDCARD_VALUE)); + if (BinnieCore.isLepidopteryActive()) + createInoculatorRecipeForNEI(Mods.forestry.stack("serumGE", 1, OreDictionary.WILDCARD_VALUE)); + if (BinnieCore.isBotanyActive()) + createInoculatorRecipeForNEI(new ItemStack(Botany.pollen, 1, OreDictionary.WILDCARD_VALUE)); + } + + @Override + public String getOverlayIdentifier() { + return "genetics.inoculator"; + } + + @Override + public String getGuiTexture() { + return "genetics:textures/gui/nei/inoculator.png"; + } + + @Override + public String getRecipeName() { + return StatCollector.translateToLocal("genetics.machine.machine.inoculator"); + } + + @Override + public void loadTransferRects() { + this.addTransferRect(75, 27, 24, 17); + } + + @Override + public void drawBackground(int recipe) { + changeToGuiTexture(); + GuiDraw.drawTexturedModalRect(0, 0, 5, 11, 166, 74); + } + + @Override + public void drawExtras(int recipe) { + this.drawProgressBar(75, 27, 176, 0, 24, 17, 40, 0); + } + + @Override + public void loadAllRecipes() { + for (InoculatorRecipe recipe : recipes) { + this.arecipes.add(new CachedInoculatorRecipe(recipe)); + } + } + + @Override + public void loadCraftingRecipes(ItemStack result) { + for (InoculatorRecipe recipe : recipes) { + if (NEIServerUtils.areStacksSameTypeCrafting(recipe.getDnaManipulable(), result)) { + this.arecipes.add(new CachedInoculatorRecipe(recipe)); + } + } + } + + @Override + public void loadUsageRecipes(FluidStack ingredient) { + if (NEIUtils.areFluidsSameType(GeneticLiquid.BacteriaVector.get(0), ingredient)) { + this.loadAllRecipes(); + } + } + + @Override + public void loadUsageRecipes(ItemStack ingredient) { + for (InoculatorRecipe recipe : recipes) { + if (NEIServerUtils.areStacksSameTypeCrafting(recipe.getDnaManipulable(), ingredient) || NEIServerUtils.areStacksSameTypeCrafting(recipe.getSerum(), ingredient)) { + this.arecipes.add(new CachedInoculatorRecipe(recipe)); + } + } + } + + private static class InoculatorRecipe { + + private final ItemStack dnaManipulable; + private final ItemStack serum; + + public InoculatorRecipe(ItemStack dnaManipulable, ItemStack serum) { + this.dnaManipulable = dnaManipulable; + this.serum = serum; + } + + public FluidStack getBacteriaVector() { + return GeneticLiquid.BacteriaVector.get(15); + } + + public ItemStack getDnaManipulable() { + return this.dnaManipulable; + } + + public ItemStack getSerum() { + return this.serum; + } + + } + + public class CachedInoculatorRecipe extends CachedBaseRecipe { + + public PositionedFluidTank bacteriaTank; + public PositionedStack serum; + public PositionedStack input; + public PositionedStack output; + public List ingredients = new ArrayList<>(); + + public CachedInoculatorRecipe(InoculatorRecipe recipe) { + + if (recipe.getSerum() != null && recipe.getDnaManipulable() != null) { + ISpeciesRoot root1 = AlleleManager.alleleRegistry.getSpeciesRoot(recipe.getDnaManipulable()); + List serums = new ArrayList<>(); + + for (ItemStack serumStack : ItemList.itemMap.get(recipe.getSerum().getItem())) { + if (serumStack.getTagCompound() != null) { + IItemSerum itemSerum = (IItemSerum) serumStack.getItem(); + ISpeciesRoot root2 = itemSerum.getSpeciesRoot(serumStack); + if (root1 == root2) serums.add(serumStack.copy()); + } + } + + this.bacteriaTank = new PositionedFluidTank(recipe.getBacteriaVector(), 100, new Rectangle(28, 6, 16, 58)); + this.serum = new PositionedStack(serums, 53, 6); + this.input = new PositionedStack(recipe.getDnaManipulable(), 53, 27); + this.output = new PositionedStack(recipe.getDnaManipulable(), 105, 27); + + this.ingredients.add(this.serum); + this.ingredients.add(this.input); + } + } + + @Override + public List getIngredients() { + this.input.setPermutationToRender(cycleticks / 40 % this.input.items.length); + this.serum.setPermutationToRender(cycleticks / 40 % this.serum.items.length); + return this.ingredients; + } + + @Override + public PositionedStack getResult() { + this.output.setPermutationToRender(cycleticks / 40 % this.output.items.length); + return this.output; + } + + @Override + public PositionedFluidTank getFluidTank() { + return this.bacteriaTank; + } + + } + +} diff --git a/src/main/java/binnie/genetics/nei/IsolatorRecipeHandler.java b/src/main/java/binnie/genetics/nei/IsolatorRecipeHandler.java new file mode 100644 index 00000000..38e794dd --- /dev/null +++ b/src/main/java/binnie/genetics/nei/IsolatorRecipeHandler.java @@ -0,0 +1,203 @@ +package binnie.genetics.nei; + +import binnie.Binnie; +import binnie.botany.Botany; +import binnie.core.BinnieCore; +import binnie.core.Mods; +import binnie.core.genetics.Gene; +import binnie.core.nei.NEIUtils; +import binnie.core.nei.PositionedFluidTank; +import binnie.core.nei.PositionedStackAdv; +import binnie.core.nei.RecipeHandlerBase; +import binnie.genetics.Genetics; +import binnie.genetics.item.GeneticsItems; +import binnie.genetics.item.ItemSequence; +import codechicken.lib.gui.GuiDraw; +import codechicken.nei.NEIServerUtils; +import codechicken.nei.PositionedStack; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IChromosomeType; +import forestry.api.genetics.ISpeciesRoot; +import net.minecraft.item.ItemStack; +import net.minecraft.util.StatCollector; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.oredict.OreDictionary; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +public class IsolatorRecipeHandler extends RecipeHandlerBase { + + private static final List recipes = new ArrayList<>(); + + @Override + public void prepare() { + if (BinnieCore.isApicultureActive()) { + recipes.add(new IsolatorRecipe(Mods.forestry.stack("beeDroneGE", 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new IsolatorRecipe(Mods.forestry.stack("beePrincessGE", 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new IsolatorRecipe(Mods.forestry.stack("beeQueenGE", 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new IsolatorRecipe(Mods.forestry.stack("beeLarvaeGE", 1, OreDictionary.WILDCARD_VALUE))); + } + if (BinnieCore.isArboricultureActive()) { + recipes.add(new IsolatorRecipe(Mods.forestry.stack("sapling", 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new IsolatorRecipe(Mods.forestry.stack("pollenFertile", 1, OreDictionary.WILDCARD_VALUE))); + } + if (BinnieCore.isLepidopteryActive()) { + recipes.add(new IsolatorRecipe(Mods.forestry.stack("butterflyGE", 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new IsolatorRecipe(Mods.forestry.stack("caterpillarGE", 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new IsolatorRecipe(Mods.forestry.stack("serumGE", 1, OreDictionary.WILDCARD_VALUE))); + } + if (BinnieCore.isBotanyActive()) { + recipes.add(new IsolatorRecipe(new ItemStack(Botany.flowerItem, 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new IsolatorRecipe(new ItemStack(Botany.seed, 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new IsolatorRecipe(new ItemStack(Botany.pollen, 1, OreDictionary.WILDCARD_VALUE))); + } + } + + @Override + public String getOverlayIdentifier() { + return "genetics.isolator"; + } + + @Override + public String getGuiTexture() { + return "genetics:textures/gui/nei/isolator.png"; + } + + @Override + public String getRecipeName() { + return StatCollector.translateToLocal("genetics.machine.machine.isolator"); + } + + @Override + public void loadTransferRects() { + this.addTransferRect(87, 27, 24, 17); + } + + @Override + public void drawBackground(int recipe) { + changeToGuiTexture(); + GuiDraw.drawTexturedModalRect(0, 0, 5, 11, 166, 74); + } + + @Override + public void drawExtras(int recipe) { + this.drawProgressBar(87, 27, 176, 0, 24, 17, 40, 0); + } + + @Override + public void loadAllRecipes() { + for (IsolatorRecipe recipe : recipes) { + this.arecipes.add(new CachedIsolatorRecipe(recipe)); + } + } + + @Override + public void loadCraftingRecipes(ItemStack result) { + if (NEIServerUtils.areStacksSameTypeCrafting(new ItemStack(Genetics.itemSequencer), result)) { + for (IsolatorRecipe recipe : recipes) { + this.arecipes.add(new CachedIsolatorRecipe(recipe)); + } + } + } + + @Override + public void loadUsageRecipes(FluidStack ingredient) { + if (NEIUtils.areFluidsSameType(Binnie.Liquid.getLiquidStack("bioethanol", 0), ingredient)) { + this.loadAllRecipes(); + } + } + + @Override + public void loadUsageRecipes(ItemStack ingredient) { + if (NEIServerUtils.areStacksSameTypeCrafting(GeneticsItems.EmptySequencer.get(1), ingredient) || NEIServerUtils.areStacksSameTypeCrafting(GeneticsItems.Enzyme.get(1), ingredient)) { + this.loadAllRecipes(); + } else { + for (IsolatorRecipe recipe : recipes) { + if (NEIServerUtils.areStacksSameTypeCrafting(recipe.getInput(), ingredient)) { + this.arecipes.add(new CachedIsolatorRecipe(recipe)); + } + } + } + } + + private static class IsolatorRecipe { + + private final ItemStack input; + + public IsolatorRecipe(ItemStack input) { + this.input = input; + } + + public ItemStack getInput() { + return this.input; + } + + public ItemStack getOutputSequencer() { + ISpeciesRoot root = AlleleManager.alleleRegistry.getSpeciesRoot(this.input); + + IChromosomeType speciesChromosomeType = root.getKaryotypeKey(); + IAllele[] defaultTemplate = root.getDefaultTemplate(); + IAllele species = defaultTemplate[speciesChromosomeType.ordinal()]; + + return ItemSequence.create(new Gene(species, speciesChromosomeType, root)); + } + + public FluidStack getEthanol() { + return Binnie.Liquid.getLiquidStack("bioethanol", 10); + } + + public ItemStack getEnzyme() { + return GeneticsItems.Enzyme.get(1); + } + + public ItemStack getEmptySequencer() { + return GeneticsItems.EmptySequencer.get(1); + } + + } + + public class CachedIsolatorRecipe extends CachedBaseRecipe { + + public PositionedFluidTank ethanolTank; + public PositionedStack emptySequencer; + public PositionedStack input; + public PositionedStack enzyme; + public PositionedStack output; + public List ingredients = new ArrayList<>(); + + public CachedIsolatorRecipe(IsolatorRecipe recipe) { + this.ethanolTank = new PositionedFluidTank(recipe.getEthanol(), 100, new Rectangle(40, 6, 16, 58)); + this.emptySequencer = new PositionedStack(recipe.getEmptySequencer(), 65, 27); + this.enzyme = new PositionedStack(recipe.getEnzyme(), 65, 48); + + if (recipe.getInput() != null) { + this.input = new PositionedStackAdv(recipe.getInput(), 65, 6) + .addToTooltip(StatCollector.translateToLocal("genetics.nei.tip.loss") + " 5%"); + this.output = new PositionedStack(recipe.getOutputSequencer(), 117, 27); + + this.ingredients.add(this.emptySequencer); + this.ingredients.add(this.input); + this.ingredients.add(this.enzyme); + } + } + + @Override + public List getIngredients() { + return getCycledIngredients(cycleticks / 40, this.ingredients); + } + + @Override + public PositionedStack getResult() { + this.output.setPermutationToRender(cycleticks / 40 % this.output.items.length); + return this.output; + } + + @Override + public PositionedFluidTank getFluidTank() { + return this.ethanolTank; + } + } +} \ No newline at end of file diff --git a/src/main/java/binnie/genetics/nei/NEIGeneticsConfig.java b/src/main/java/binnie/genetics/nei/NEIGeneticsConfig.java new file mode 100644 index 00000000..27b40b6f --- /dev/null +++ b/src/main/java/binnie/genetics/nei/NEIGeneticsConfig.java @@ -0,0 +1,39 @@ +package binnie.genetics.nei; + +import binnie.core.BinnieCore; +import binnie.core.nei.RecipeHandlerBase; +import codechicken.nei.api.API; +import codechicken.nei.api.IConfigureNEI; + +public class NEIGeneticsConfig implements IConfigureNEI { + protected static void registerHandler(RecipeHandlerBase handler) { + handler.prepare(); + API.registerRecipeHandler(handler); + API.registerUsageHandler(handler); + } + + @Override + public void loadConfig() { + registerHandler(new IsolatorRecipeHandler()); + registerHandler(new SequencerRecipeHandler()); + registerHandler(new PolymeriserRecipeHandler()); + registerHandler(new InoculatorRecipeHandler()); + registerHandler(new AnalyserRecipeHandler()); + registerHandler(new IncubatorRecipeHandler()); + registerHandler(new GenepoolRecipeHandler()); + registerHandler(new AcclimatiserRecipeHandler()); + registerHandler(new SplicerRecipeHandler()); + registerHandler(new DatabaseRecipeHandler()); + } + + @Override + public String getName() { + return "Genetics NEI"; + } + + @Override + public String getVersion() { + return BinnieCore.VERSION; + } + +} \ No newline at end of file diff --git a/src/main/java/binnie/genetics/nei/PolymeriserRecipeHandler.java b/src/main/java/binnie/genetics/nei/PolymeriserRecipeHandler.java new file mode 100644 index 00000000..f65ebd56 --- /dev/null +++ b/src/main/java/binnie/genetics/nei/PolymeriserRecipeHandler.java @@ -0,0 +1,200 @@ +package binnie.genetics.nei; + +import binnie.core.nei.NEIUtils; +import binnie.core.nei.PositionedFluidTank; +import binnie.core.nei.PositionedStackAdv; +import binnie.core.nei.RecipeHandlerBase; +import binnie.genetics.Genetics; +import binnie.genetics.api.IItemSerum; +import binnie.genetics.genetics.Engineering; +import binnie.genetics.item.GeneticLiquid; +import binnie.genetics.item.ItemSequence; +import codechicken.lib.gui.GuiDraw; +import codechicken.nei.ItemList; +import codechicken.nei.NEIServerUtils; +import codechicken.nei.PositionedStack; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.util.StatCollector; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.oredict.OreDictionary; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +public class PolymeriserRecipeHandler extends RecipeHandlerBase { + + private static final List recipes = new ArrayList<>(); + + @Override + public void prepare() { + recipes.add(new PolymeriserRecipe(new ItemStack(Genetics.itemSequencer, 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new PolymeriserRecipe(new ItemStack(Genetics.itemSerum, 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new PolymeriserRecipe(new ItemStack(Genetics.itemSerumArray, 1, OreDictionary.WILDCARD_VALUE))); + } + + @Override + public String getOverlayIdentifier() { + return "genetics.polymeriser"; + } + + @Override + public String getGuiTexture() { + return "genetics:textures/gui/nei/polymeriser.png"; + } + + @Override + public String getRecipeName() { + return StatCollector.translateToLocal("genetics.machine.machine.polymeriser"); + } + + @Override + public void loadTransferRects() { + this.addTransferRect(95, 27, 24, 17); + } + + @Override + public void drawBackground(int recipe) { + changeToGuiTexture(); + GuiDraw.drawTexturedModalRect(0, 0, 5, 11, 166, 74); + } + + @Override + public void drawExtras(int recipe) { + this.drawProgressBar(95, 27, 176, 0, 24, 17, 40, 0); + } + + @Override + public void loadAllRecipes() { + for (PolymeriserRecipe recipe : recipes) { + this.arecipes.add(new CachedPolymeriserRecipe(recipe)); + } + } + + @Override + public void loadCraftingRecipes(ItemStack result) { + for (PolymeriserRecipe recipe : recipes) { + if (NEIServerUtils.areStacksSameTypeCrafting(recipe.getOutput(), result)) { + this.arecipes.add(new CachedPolymeriserRecipe(recipe)); + } + } + } + + @Override + public void loadUsageRecipes(ItemStack ingredient) { + if (NEIServerUtils.areStacksSameTypeCrafting(new ItemStack(Items.gold_nugget), ingredient)) { + this.loadAllRecipes(); + } else { + for (PolymeriserRecipe recipe : recipes) { + if (NEIServerUtils.areStacksSameTypeCrafting(recipe.getSerum(), ingredient)) { + this.arecipes.add(new CachedPolymeriserRecipe(recipe)); + } + } + + } + } + + @Override + public void loadUsageRecipes(FluidStack ingredient) { + if (NEIUtils.areFluidsSameType(GeneticLiquid.BacteriaPoly.get(0), ingredient) || NEIUtils.areFluidsSameType(GeneticLiquid.RawDNA.get(0), ingredient)) { + this.loadAllRecipes(); + } + } + + private static class PolymeriserRecipe { + + private final ItemStack serum; + + public PolymeriserRecipe(ItemStack serum) { + this.serum = serum; + } + + public ItemStack getSerum() { + return this.serum; + } + + public ItemStack getOutput() { + return this.serum; + } + + } + + public class CachedPolymeriserRecipe extends CachedBaseRecipe { + + public PositionedStack input; + public PositionedStack output; + public PositionedStack goldNugget; + public PositionedFluidTank bacteriaPoly; + public PositionedFluidTank rawDNA; + public List ingredients = new ArrayList<>(); + public List tanks = new ArrayList<>(); + + public CachedPolymeriserRecipe(PolymeriserRecipe recipe) { + if (recipe.getSerum() != null) { + + List inputs = new ArrayList<>(); + List outputs = new ArrayList<>(); + List bacteriaPolyTanks = new ArrayList<>(); + List rawDNATanks = new ArrayList<>(); + + for (ItemStack itemStack : ItemList.itemMap.get(recipe.getSerum().getItem())) { + if (itemStack.getTagCompound() != null) { + ItemStack temp = itemStack.copy(); + if (itemStack.getItem() instanceof IItemSerum) { + temp.setItemDamage(itemStack.getMaxDamage()); + } + + inputs.add(temp); + int bacteriaPolyAmount = 10 * temp.getItemDamage() * (temp.getTagCompound() == null ? 1 : Engineering.getGenes(temp).length); + bacteriaPolyTanks.add(GeneticLiquid.BacteriaPoly.get(bacteriaPolyAmount)); + rawDNATanks.add(GeneticLiquid.RawDNA.get(bacteriaPolyAmount * 5)); + } + } + + this.input = new PositionedStack(inputs, 73, 27); + this.goldNugget = new PositionedStackAdv(new ItemStack(Items.gold_nugget), 73, 48) + .addToTooltip(StatCollector.translateToLocalFormatted("genetics.nei.tip.processSpeed", 5)); + this.ingredients.add(this.input); + this.ingredients.add(this.goldNugget); + + this.bacteriaPoly = new PositionedFluidTank(bacteriaPolyTanks, 10000, new Rectangle(27, 6, 16, 58), null, null); + this.rawDNA = new PositionedFluidTank(rawDNATanks, 20000, new Rectangle(48, 6, 16, 58), null, null); + this.tanks.add(this.bacteriaPoly); + this.tanks.add(this.rawDNA); + + for (ItemStack itemStack : ItemList.itemMap.get(recipe.getOutput().getItem())) { + if (itemStack.getTagCompound() != null) { + ItemStack temp = itemStack.copy(); + if (recipe.getOutput().getItem() instanceof ItemSequence) { + temp.setItemDamage(0); + } + outputs.add(temp); + } + } + this.output = new PositionedStack(outputs, 125, 27); + } + } + + @Override + public List getIngredients() { + this.input.setPermutationToRender(cycleticks / 40 % this.input.items.length); + this.bacteriaPoly.setPermutationToRender(cycleticks / 40 % this.bacteriaPoly.tanks.length); + this.rawDNA.setPermutationToRender(cycleticks / 40 % this.rawDNA.tanks.length); + return this.ingredients; + } + + @Override + public PositionedStack getResult() { + this.output.setPermutationToRender(cycleticks / 40 % this.output.items.length); + return this.output; + } + + @Override + public List getFluidTanks() { + return this.tanks; + } + + } + +} diff --git a/src/main/java/binnie/genetics/nei/SequencerRecipeHandler.java b/src/main/java/binnie/genetics/nei/SequencerRecipeHandler.java new file mode 100644 index 00000000..1a17329b --- /dev/null +++ b/src/main/java/binnie/genetics/nei/SequencerRecipeHandler.java @@ -0,0 +1,116 @@ +package binnie.genetics.nei; + +import binnie.core.nei.RecipeHandlerBase; +import binnie.genetics.Genetics; +import binnie.genetics.item.GeneticsItems; +import codechicken.lib.gui.GuiDraw; +import codechicken.nei.ItemList; +import codechicken.nei.NEIServerUtils; +import codechicken.nei.PositionedStack; +import net.minecraft.item.ItemStack; +import net.minecraft.util.StatCollector; + +import java.util.ArrayList; +import java.util.List; + +public class SequencerRecipeHandler extends RecipeHandlerBase { + + @Override + public String getOverlayIdentifier() { + return "genetics.sequencer"; + } + + @Override + public String getGuiTexture() { + return "genetics:textures/gui/nei/sequencer.png"; + } + + @Override + public String getRecipeName() { + return StatCollector.translateToLocal("genetics.machine.machine.sequencer"); + } + + @Override + public void loadTransferRects() { + this.addTransferRect(75, 19, 24, 17); + } + + @Override + public void drawBackground(int recipe) { + changeToGuiTexture(); + GuiDraw.drawTexturedModalRect(0, 0, 5, 11, 166, 74); + } + + @Override + public void drawExtras(int recipe) { + this.drawProgressBar(75, 19, 176, 0, 24, 17, 40, 0); + } + + @Override + public void loadAllRecipes() { + this.arecipes.add(new CachedSequencerRecipe()); + } + + @Override + public void loadCraftingRecipes(ItemStack result) { + if (NEIServerUtils.areStacksSameTypeCrafting(GeneticsItems.EmptySequencer.get(1), result)) { + this.loadAllRecipes(); + } + } + + @Override + public void loadUsageRecipes(ItemStack ingredient) { + if (NEIServerUtils.areStacksSameTypeCrafting(new ItemStack(Genetics.itemSequencer), ingredient) + || NEIServerUtils.areStacksSameTypeCrafting(GeneticsItems.FluorescentDye.get(1), ingredient) + || NEIServerUtils.areStacksSameTypeCrafting(new ItemStack(Genetics.database), ingredient)) { + this.loadAllRecipes(); + } + } + + public class CachedSequencerRecipe extends CachedBaseRecipe { + + public PositionedStack seq; + public PositionedStack fluorescentDye = new PositionedStack(GeneticsItems.FluorescentDye.get(1), 53, 40); + public PositionedStack database = new PositionedStack(new ItemStack(Genetics.database), 105, 19); + public PositionedStack emptySeq = new PositionedStack(GeneticsItems.EmptySequencer.get(1), 105, 40); + public List ingredients = new ArrayList<>(); + public List results = new ArrayList<>(); + + public CachedSequencerRecipe() { + List seqList = new ArrayList<>(); + + for (ItemStack itemStack : ItemList.itemMap.get(Genetics.itemSequencer)) { + for (int i = Genetics.itemSequencer.getMaxDamage(); i >= 0; i--) { + ItemStack temp = itemStack.copy(); + temp.setItemDamage(i); + seqList.add(temp); + } + } + + this.seq = new PositionedStack(seqList, 53, 19); + + this.ingredients.add(this.seq); + this.ingredients.add(this.fluorescentDye); + + this.results.add(this.database); + this.results.add(this.emptySeq); + } + + @Override + public PositionedStack getResult() { + return null; + } + + @Override + public List getIngredients() { + this.seq.setPermutationToRender(cycleticks / 40 % this.seq.items.length); + return this.ingredients; + } + + @Override + public List getOtherStacks() { + return this.results; + } + } + +} diff --git a/src/main/java/binnie/genetics/nei/SplicerRecipeHandler.java b/src/main/java/binnie/genetics/nei/SplicerRecipeHandler.java new file mode 100644 index 00000000..361bcbc0 --- /dev/null +++ b/src/main/java/binnie/genetics/nei/SplicerRecipeHandler.java @@ -0,0 +1,177 @@ +package binnie.genetics.nei; + +import binnie.botany.Botany; +import binnie.core.BinnieCore; +import binnie.core.Mods; +import binnie.core.nei.NEIUtils; +import binnie.core.nei.PositionedFluidTank; +import binnie.core.nei.RecipeHandlerBase; +import binnie.genetics.Genetics; +import binnie.genetics.api.IItemSerum; +import binnie.genetics.item.GeneticLiquid; +import codechicken.lib.gui.GuiDraw; +import codechicken.nei.ItemList; +import codechicken.nei.NEIServerUtils; +import codechicken.nei.PositionedStack; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.ISpeciesRoot; +import net.minecraft.item.ItemStack; +import net.minecraft.util.StatCollector; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.oredict.OreDictionary; + +import java.util.ArrayList; +import java.util.List; + +public class SplicerRecipeHandler extends RecipeHandlerBase { + + private static final List recipes = new ArrayList<>(); + + private void createInoculatorRecipeForNEI(ItemStack dnaManipulable) { + recipes.add(new SplicerRecipe(dnaManipulable, new ItemStack(Genetics.itemSerum, 1, OreDictionary.WILDCARD_VALUE))); + recipes.add(new SplicerRecipe(dnaManipulable, new ItemStack(Genetics.itemSerumArray, 1, OreDictionary.WILDCARD_VALUE))); + } + + @Override + public void prepare() { + if (BinnieCore.isApicultureActive()) + createInoculatorRecipeForNEI(Mods.forestry.stack("beeLarvaeGE", 1, OreDictionary.WILDCARD_VALUE)); + if (BinnieCore.isArboricultureActive()) + createInoculatorRecipeForNEI(Mods.forestry.stack("pollenFertile", 1, OreDictionary.WILDCARD_VALUE)); + if (BinnieCore.isLepidopteryActive()) + createInoculatorRecipeForNEI(Mods.forestry.stack("serumGE", 1, OreDictionary.WILDCARD_VALUE)); + if (BinnieCore.isBotanyActive()) + createInoculatorRecipeForNEI(new ItemStack(Botany.pollen, 1, OreDictionary.WILDCARD_VALUE)); + } + + @Override + public String getOverlayIdentifier() { + return "genetics.splicer"; + } + + @Override + public String getGuiTexture() { + return "genetics:textures/gui/nei/splicer.png"; + } + + @Override + public String getRecipeName() { + return StatCollector.translateToLocal("genetics.machine.advMachine.splicer"); + } + + @Override + public void loadTransferRects() { + this.addTransferRect(75, 27, 24, 17); + } + + @Override + public void drawBackground(int recipe) { + changeToGuiTexture(); + GuiDraw.drawTexturedModalRect(0, 0, 5, 11, 166, 74); + } + + @Override + public void drawExtras(int recipe) { + this.drawProgressBar(75, 27, 176, 0, 24, 17, 40, 0); + } + + @Override + public void loadAllRecipes() { + for (SplicerRecipe recipe : recipes) { + this.arecipes.add(new CachedSplicer(recipe)); + } + } + + @Override + public void loadCraftingRecipes(ItemStack result) { + for (SplicerRecipe recipe : recipes) { + if (NEIServerUtils.areStacksSameTypeCrafting(recipe.getDnaManipulable(), result)) { + this.arecipes.add(new CachedSplicer(recipe)); + } + } + } + + @Override + public void loadUsageRecipes(FluidStack ingredient) { + if (NEIUtils.areFluidsSameType(GeneticLiquid.BacteriaVector.get(0), ingredient)) { + this.loadAllRecipes(); + } + } + + @Override + public void loadUsageRecipes(ItemStack ingredient) { + for (SplicerRecipe recipe : recipes) { + if (NEIServerUtils.areStacksSameTypeCrafting(recipe.getDnaManipulable(), ingredient) || NEIServerUtils.areStacksSameTypeCrafting(recipe.getSerum(), ingredient)) { + this.arecipes.add(new CachedSplicer(recipe)); + } + } + } + + private static class SplicerRecipe { + private final ItemStack dnaManipulable; + private final ItemStack serum; + + public SplicerRecipe(ItemStack dnaManipulable, ItemStack serum) { + this.dnaManipulable = dnaManipulable; + this.serum = serum; + } + + public ItemStack getDnaManipulable() { + return this.dnaManipulable; + } + + public ItemStack getSerum() { + return this.serum; + } + + } + + public class CachedSplicer extends CachedBaseRecipe { + + public PositionedFluidTank bacteriaTank; + public PositionedStack serum; + public PositionedStack input; + public PositionedStack output; + public List ingredients = new ArrayList<>(); + + public CachedSplicer(SplicerRecipe recipe) { + if (recipe.getSerum() != null && recipe.getDnaManipulable() != null) { + ISpeciesRoot root1 = AlleleManager.alleleRegistry.getSpeciesRoot(recipe.getDnaManipulable()); + List serums = new ArrayList<>(); + + for (ItemStack serumStack : ItemList.itemMap.get(recipe.getSerum().getItem())) { + if (serumStack.getTagCompound() != null) { + IItemSerum itemSerum = (IItemSerum) serumStack.getItem(); + ISpeciesRoot root2 = itemSerum.getSpeciesRoot(serumStack); + if (root1 == root2) serums.add(serumStack.copy()); + } + } + + this.serum = new PositionedStack(serums, 53, 40); + this.input = new PositionedStack(recipe.getDnaManipulable(), 53, 14); + this.output = new PositionedStack(recipe.getDnaManipulable(), 105, 27); + + this.ingredients.add(this.serum); + this.ingredients.add(this.input); + } + } + + @Override + public List getIngredients() { + this.input.setPermutationToRender(cycleticks / 40 % this.input.items.length); + this.serum.setPermutationToRender(cycleticks / 40 % this.serum.items.length); + return this.ingredients; + } + + @Override + public PositionedStack getResult() { + this.output.setPermutationToRender(cycleticks / 40 % this.output.items.length); + return this.output; + } + + @Override + public PositionedFluidTank getFluidTank() { + return this.bacteriaTank; + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/genetics/lang/en_US.lang b/src/main/resources/assets/genetics/lang/en_US.lang index 5a165ded..0cf42f51 100644 --- a/src/main/resources/assets/genetics/lang/en_US.lang +++ b/src/main/resources/assets/genetics/lang/en_US.lang @@ -266,3 +266,12 @@ genetics.gui.analyst.wood.flammable=Flammable genetics.gui.analyst.wood.logs=Logs genetics.gui.analyst.wood.products=Refined Products genetics.gui.analyst.wood.noFruits=This tree has no\nfruits or nuts + +genetics.nei.tip.loss=Loss: +genetics.nei.tip.noConsume=Not Be Consumed +genetics.nei.tip.effect=Effect: %s +genetics.nei.tip.temperature=Temperature +genetics.nei.tip.humidity=Humidity +genetics.nei.tip.processSpeed=%dx Processing Speed +genetics.nei.tip.rf=%dx Processing Speed +genetics.nei.tip.databaseDesc=Open the database and pick up an empty serum. Click the serum on Sequenced gene to apply. \ No newline at end of file diff --git a/src/main/resources/assets/genetics/textures/gui/nei/acclimatiser.png b/src/main/resources/assets/genetics/textures/gui/nei/acclimatiser.png new file mode 100644 index 0000000000000000000000000000000000000000..caf49b18f59f17ad798521893095d0dcae79d622 GIT binary patch literal 9892 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 F{ue*sI>-P3 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/genetics/textures/gui/nei/analyser.png b/src/main/resources/assets/genetics/textures/gui/nei/analyser.png new file mode 100644 index 0000000000000000000000000000000000000000..46607802e3d6875697c409ed5e1e040f90d19722 GIT binary patch literal 12174 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�im7F@kA>c- zW6kIKNS5Nd(S!hS-Od4p#|e)C6}0W2U*mrxa*B8KW)8(s1$v+-GLF@-?%C1|v^i6U z03MJmJppV__XBg&{Ib!O@PUy%!&`1_o4xi z{7&q4{9FCyLJDPadf&x#jh>OQ&XMrN!@!TmA1^1+Ozk5)^%U8U$1KZ8a_%z@@5-y< zDBH>UIy1SY0YsOU>K#Jx4WvozWb3PCx0>Y0HbDTg;Sifs?3Ne!8&|=;u@fO}%GOU^ zWshI^MB$G!$Dn6J#+RzU=+r#N=fYp+)?nib8CMox;xWFHsHKA=DvP7+h+%18gkoBT zmF-pth=2o|5+h&-U=hj!{%oS?+UF%gc3BhNkY_g~J^M*!o;qOc$iMTM!}Y)`Ocej` bE}i~sS1CGh>hdS(p9X45+KLtOmSO(|hxwt; literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/genetics/textures/gui/nei/database.png b/src/main/resources/assets/genetics/textures/gui/nei/database.png new file mode 100644 index 0000000000000000000000000000000000000000..4c0c84193202ac3216cca9c2b770ccd451a077af GIT binary patch literal 7462 zcmeHMc|4R~+aFt&7G*12wxn(LeIl~d$dZ^sX&E#3Fqj$4Fer@{DM^teWT#S*>{MDT zE!N6XA`v1&h>E=TQ2pxjK7YKw_j!KLU!BiqX6|#H>-wH^eb4vY=bX=+u(95}P)0=t z0)Z?vC!5+rAR^$S2t-N@{BghLK!HG{qXQ@oJX6Yyg)AP~Qo zgBNy1suCBO%@l_^ikc4>t8LI>Najuv_ieeE7HQx+-fZgNru*#C3aJj!rTg+7XFgBh zW;%6r{p6itS2F0IkE&#HUMcJkd|6CVtsVd7Rrvl1ceH3c?Eb1|Q}e>@6TKhI!hBAZ zPOi8d)@mxac=?S=puaq?l}yp8tGOkeiQm|nEzOs&hvj-?>Kew?H)Cr{le@nt-zIOk zsbSncqmF8iiwNnQmeY&A`p` z*_+y|i2Pg4FN_Oe^BN;-rnI#`e%^5>`10~3+~AFiL!OQP9WP-;eX*_Vi(W;CLhr%5 z(D-&)crP_#;HpN-q{MW|AewBwdLMDoz{V+)rTl{HzA?GGsJ(rDjq8sRPn|TJjy2qU zqcGzzw?O|u@SgUox!X)4o~_M3bi5URsj{o%>%??wk&M))@tYasikxY=hSab3#Jz)* z_JoDmmlWx9L_L@6+8pI2Dw@=@qU5c|rw!{vbml{_6uqqnBt@2{Ca&r`LKcnd^l^`- z^Y@H5jJ6D`p~Oy*D}ftY&5*T6$y0A_jwdVW9$Q8WB}O~YEFz6VSEt8EDeQ_?vkWJ8 z$6I6-D-v?cBe%fPpFhpa7G+k(x@Dy|y;RwcTY=w!-{X4yE6iZbHK4!v{GR=)N9&|? z!Z9CLrH13Cqof7Zn9+5)wFR%VqjorWrJu8R^vSon%tEdoD0)^~I#ALomalqk?;Sx< zY-w_jtnC-)gGrUo;)k^3pPEyuAz^Dejr7-wi|5%_dw6O2nOP%q8_y~>q|zzX8FuAH zh;_YPzWjl(vc=oqep|v`8M5@%6h8tj)25+4p;)-}vK7>%OVbxfCN;{uC{%hW-&wxD zB`V$4V@*~CGBD=R8O7F+gxxB;+t#pxN&Sym-FMzB^YPwm5*xYrhOyh0gj2U7Z{JQV zr6Q4k)%XRO)GAqh$y1m5@+s(qhoyluCuzPy_S3z6*0nSWzYuwP_jL-hj+tX!i&Yi-U z=E0i6Pjz}j)78`{gB5w0NBM+`It5I|wE6m8(r39R;p}4r8N0RM4qCN`rMC6AtTmOB zxW|GLy~H{BJFm2)Mwl(Xzp9n5l>OK`(0KC_*rPiU>u@e8NElKK5|1ogDD zEQ8%KFJ0-4v9;wFcitGPg!V2FDNQPC3%()klGY)wcV^PZ#D62ctIAX?l&w;-&w+3g zczGso$Mdt0O$iC3m`||Unl;Ak@ngzYIf4+wLs&^EV@t)?lO2{0%*}({yM|D!akbZN z?P3DAK{L5KrSek5`|Fn-(>xvAWNl&*owZ~kK4opML2lKKfC_b+2K?)_yA#qrV6~l6 zzAc%_3x=gcZ2IJuykl5rYvxJuNY;JKGTp=89aWYwg$+#}*sw;GZrB!ewsiR2bBut@ zr|T9rwdeUh@j9lgi|=o|+*+|=%T}~w=7%&lTRj!gvsEh(MZ14ur!5POK!xh$8nf9= zH|lerDR0FeR+w^lw|D8CM!ACBk4qbA`iJuPDLiN1i8j>(Q^Ug}*#Y>+cipqL4CrPU z^~Jx9kOe*!8KKQIj8&p|nK2JiSutk5EQ|Vmrzh+;Y;L=06De{%Lq6k^QdZdQ5-Y!i z*d~QDmT5Se#L~LUx8x}6&u1KyG&R0f+Gv}W8DQD@eB&BdBTv%BE4k+`8NEN-dCL|` z%ny;xvMO&avYvEb!E`SP~JvzOu5I5yvs!SGK=h55LZTg19IysuxJc2*Q) zXBhcLS(pI|alI?~ zguOFe!b*jMH@Jqe7JR+1S`fA~B@5C-zjk*kPp!P@(Gc){%})CY(WGr_m*A!Pbh6Ke zuYGOYu3z!3_4t~DPN<3P)h;6}-`hHoHdyAWHqpMMPjY01P?0#-*Z!4jS9VQrnyDXQ zVhrQ_R5VWb-5-kxRY{5}D+n*E&V7(DRq^JW(q7Z-WqkV6`@K2sx!t%}cprCb0{?9G zt74bhrZOPDy14t)=NLkr|7cw5h++42JCsIsdd0_cC3_4Qu=BS++A}xz`}#JIV3l5H z64TJSv8Z5Ycz&{ln`q9w+Kq&Ym8dMg^U&T)jhKbS*2${o26+}$B=b?bSLdd#2ypef zR@R4kz~VDUYo&W)^z7Deaw6ws3{Tnw9yWj1QLtut#;*8K20kKuah+s|cKd6WOZT1o zE2=Im$Z5JFc#)Le5@#Zp((?S)fXZ_&1|XB;nZ66-_MGnDqP(45+edH|395NA8s>kY z|Hx?deGhBL5QZMl!Bsi`&Nca(xaUmo!I1VE;uowMd-fxG*UaogQuK7P}>6Mb6dNPoSZ2PuA97& zXgQ5M*z>4ba5T|B`rFoFbfVrjHN(-yn?rA0?hK4rO;xu=Kfd63DVmt!x#R7%yN;nH zE0VMFIz;u%;sjrgR5%V}_FnRM<%N;8mmEo5kV9KI=t&$mbK{?uR#teNEa*}8_KAA( zblx4?^kn0Xow0(l>Yj~x?t6~@~%eW8fdz%9Bo!UPi2ievWm zdpFLUKRjk>FfMTVwp2rqvUc?O!26tBEJt8nqHVc!in)c%lc}*-@+z({Ls&@rtI&MNKDWYF&M-GR=7MR>!XL{m7fPQ|= zvEIp&kki@xB?;YuAL<&ezO|e;Y1&E5P*ob4H!_xy&TZFQl#`OSI8pwzGH+w&=By{M zGA|fm-Ej4p2GEZZCSeEonyqNBN?(V~!AQ=idTw_Z1Am6=5Pw!RQ zK81G&at2Q?(Y!Gq<5n;o=+Syg{_e~ICni*ozNq>@gI0G<0mM3_khCuWU{XD5OcYvqq47f1a2HHcV zW!jodx`DPm)(T^rM*E$Q{S7;AlaI3`VIls476Q& zJWmoF&gb)Cd^C*X?E*&f_g0?uN=e~sYs%zQzR?*sam5nKv* z@qpU`T#k=74KVWs*gTzIA?UQ9@t!{39<%AtX>h;;V1ce&uvg@7U2ZnFviTVyq`-yA z@|=wV$^Olg$7K9P)^B4Iw#=sU>p;NppSZty|HysT8T7KUBAIe%KEmOdn;K{f`zO&k zG$x%i`^caX30MY!0HqV1(NGKli-HpAI69O8;PF%p4S~WEF~2~Wv$;Gfn+6D>KyVln z#33T6I4T3<3`NrML?{M_Awr2XDiTU000ca!E+WPm_yuCCHxpDP)#KMu38Cm96o!Fy zrZbRqC>6<|Loo<64NAoTG$?_Aq0$(1fJUbhXQAjc(k6~KiwaIBlSOp_;GS%k*#;ru zq>VP_2HGeX;xCJh2bISF1Hd)FWYal(?q5w5CJV6RQH6XWaabG{fg}*{L?RMPm`i*X zaR=bd1+^$dMIvD6Ib`9)kic|6YNgr+cZR^XcY zbJId*azPJ&q2|A<-VX4ZtIaI}59Vx>rsk}0NmSZgCtRv8K%eahjGJqsxl-9K0Jy@x zOX`Q6`7fpm=ZvG$5J-?&Is<@W&@^zyF*pX4hCpL5IDkM$(^0>pb2$tipXv>4bOAF3 zvjHVEn~mnG?_{q2-JkCY2$@2F>l=ZCqOcSsj)X;!P(*F`Kc5~IjmBefC@d61b4Efj zSWrSlItmZPJ2L-!%p-(M2{U=JYlpHBW3zklfZL)YJ8;BPtqQP&^3{uTp&%lVJG{$q5>{B;)x z*x>P;58kwE!@A#sw{#yHONyEBx=t5<&6Uc^%9AHg&dkiXy1HumtKji?u==xrt#jq4 zW$pnq{%Qfk!76A35e~fZHGGBx!37Y=_U+q2SP(NzEt3nHM0mE=b`YbU7Vtkdh={Yr zW>d&<33W19k@h4zf*$kbg&z?}Z2U6ND9JOoGL!6?r#^ofTpV!L2V?N&rW+~X-*YdJ z;SV$w%(meV)L(n>buSHL7V1FhN?PFGOJUzAKPS<$A-pEfe%jxwD>_i)EM(d@=v2?^ z))htqlc0i=qw(VJ3dQnj#KtBe25asf@FL6BKNAZ}f^=1Izr8rwA@y2f(uVj1783{mJKb4^E%MpqJ`wr}Uzgp;TZf0$oWxVh3{{Tk=sha=* literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/genetics/textures/gui/nei/genepool.png b/src/main/resources/assets/genetics/textures/gui/nei/genepool.png new file mode 100644 index 0000000000000000000000000000000000000000..a1b265b717f80c9857425883347303542033bc0d GIT binary patch literal 8216 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 US9T}nCNCRUnA(`+8+jc2FG!NTzyJUM literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/genetics/textures/gui/nei/isolator.png b/src/main/resources/assets/genetics/textures/gui/nei/isolator.png new file mode 100644 index 0000000000000000000000000000000000000000..e51f4a78223f61f45a6bc536fc6ad54c69c299ae GIT binary patch literal 8323 zcmeHMc{tSF+aJ5^yC@li$S}K^F(QmDA|$jKvoM&&%-D$}g_1-i5}{^kjii{W7zhNC zw6nEx0fG2{E+0r#0Qd71$B&s6ZJh(2zP%w+lq|yQ@U~V{z0;Yt~s31^S@Azp? z_8L>U_*X$mSpF~kDF;wK4CsS%<(=yxX=yQArjfErjv-kuj}}(JHzrdT-o5IZPrh}! z+8AcnjPh;WTUt5SWLMd}*W}!zrs?oS&ee{KlkKmcawOK?3(kAf=lXT>Wf$~0>d})! z`&;UE^E#CM8&YmINN}?@@RIPl(`e@#k_z*|cU}tnbzcd*OxVQ8D<8#7u7Py-@oZ8N zUr4Fli#8e&h)%!+FJp@sl6r-pph6&D{uk&vDzzGizJhs^yq-b8n;R6i;t%ZXohx^p`e6 zueNyHD|GOy7VPVrj}&mhFayZWp|h(k9+gb#lRtxMX@|xe5=tHkbcZ~4?CuX4U3+Ma z0c?)az#3loI27d>H~YcHdH(#({x5R=r}JXpVk#aCss{x5_WB>fRx46-Qg+@TK`(}X zdU@*Ggh1p*#q8?0vKybjy&;@M*}$G_rh|vSK#JZA&i;s4aNQ*!s≪r9iG{pXB2c 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/genetics/textures/gui/nei/polymeriser.png b/src/main/resources/assets/genetics/textures/gui/nei/polymeriser.png new file mode 100644 index 0000000000000000000000000000000000000000..20ccb5a514c74109d096dc840a7f3f63047f1a31 GIT binary patch literal 8488 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 literal 0 HcmV?d00001