aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/me/Danker/features/puzzlesolvers
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/me/Danker/features/puzzlesolvers')
-rw-r--r--src/main/java/me/Danker/features/puzzlesolvers/ArrowTerminalSolver.java32
-rw-r--r--src/main/java/me/Danker/features/puzzlesolvers/BlazeSolver.java86
-rw-r--r--src/main/java/me/Danker/features/puzzlesolvers/BlockPlacingFlowers.java44
-rw-r--r--src/main/java/me/Danker/features/puzzlesolvers/BlockWrongTerminalClicks.java112
-rw-r--r--src/main/java/me/Danker/features/puzzlesolvers/BoulderSolver.java188
-rw-r--r--src/main/java/me/Danker/features/puzzlesolvers/ChronomatronSolver.java114
-rw-r--r--src/main/java/me/Danker/features/puzzlesolvers/ClickInOrderSolver.java107
-rw-r--r--src/main/java/me/Danker/features/puzzlesolvers/CreeperSolver.java86
-rw-r--r--src/main/java/me/Danker/features/puzzlesolvers/LividSolver.java89
-rw-r--r--src/main/java/me/Danker/features/puzzlesolvers/SelectAllColourSolver.java59
-rw-r--r--src/main/java/me/Danker/features/puzzlesolvers/StartsWithSolver.java31
-rw-r--r--src/main/java/me/Danker/features/puzzlesolvers/SuperpairsSolver.java150
-rw-r--r--src/main/java/me/Danker/features/puzzlesolvers/ThreeManSolver.java75
-rw-r--r--src/main/java/me/Danker/features/puzzlesolvers/TicTacToeSolver.java135
-rw-r--r--src/main/java/me/Danker/features/puzzlesolvers/TriviaSolver.java102
-rw-r--r--src/main/java/me/Danker/features/puzzlesolvers/UltrasequencerSolver.java112
-rw-r--r--src/main/java/me/Danker/features/puzzlesolvers/WaterSolver.java162
17 files changed, 1684 insertions, 0 deletions
diff --git a/src/main/java/me/Danker/features/puzzlesolvers/ArrowTerminalSolver.java b/src/main/java/me/Danker/features/puzzlesolvers/ArrowTerminalSolver.java
new file mode 100644
index 0000000..35458f3
--- /dev/null
+++ b/src/main/java/me/Danker/features/puzzlesolvers/ArrowTerminalSolver.java
@@ -0,0 +1,32 @@
+package me.Danker.features.puzzlesolvers;
+
+import me.Danker.commands.ToggleCommand;
+import me.Danker.utils.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.entity.item.EntityItemFrame;
+import net.minecraft.init.Blocks;
+import net.minecraft.init.Items;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.BlockPos;
+import net.minecraftforge.event.entity.player.EntityInteractEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+
+public class ArrowTerminalSolver {
+
+ @SubscribeEvent
+ public void onEntityInteract(EntityInteractEvent event) {
+ Minecraft mc = Minecraft.getMinecraft();
+ if (mc.thePlayer != event.entityPlayer) return;
+
+ if (ToggleCommand.itemFrameOnSeaLanternsToggled && Utils.inDungeons && event.target instanceof EntityItemFrame) {
+ EntityItemFrame itemFrame = (EntityItemFrame) event.target;
+ ItemStack item = itemFrame.getDisplayedItem();
+ if (item == null || item.getItem() != Items.arrow) return;
+ BlockPos blockPos = Utils.getBlockUnderItemFrame(itemFrame);
+ if (mc.theWorld.getBlockState(blockPos).getBlock() == Blocks.sea_lantern) {
+ event.setCanceled(true);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/me/Danker/features/puzzlesolvers/BlazeSolver.java b/src/main/java/me/Danker/features/puzzlesolvers/BlazeSolver.java
new file mode 100644
index 0000000..0910fc7
--- /dev/null
+++ b/src/main/java/me/Danker/features/puzzlesolvers/BlazeSolver.java
@@ -0,0 +1,86 @@
+package me.Danker.features.puzzlesolvers;
+
+import me.Danker.DankersSkyblockMod;
+import me.Danker.commands.ToggleCommand;
+import me.Danker.utils.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.entity.Entity;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.StringUtils;
+import net.minecraft.world.World;
+import net.minecraftforge.client.event.RenderWorldLastEvent;
+import net.minecraftforge.event.world.WorldEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
+
+import java.util.List;
+
+public class BlazeSolver {
+
+ static Entity highestBlaze = null;
+ static Entity lowestBlaze = null;
+ public static int LOWEST_BLAZE_COLOUR;
+ public static int HIGHEST_BLAZE_COLOUR;
+
+ @SubscribeEvent
+ public void onWorldChange(WorldEvent.Load event) {
+ lowestBlaze = null;
+ highestBlaze = null;
+ }
+
+ @SubscribeEvent
+ public void onTick(TickEvent.ClientTickEvent event) {
+ if (event.phase != TickEvent.Phase.START) return;
+
+ World world = Minecraft.getMinecraft().theWorld;
+ if (DankersSkyblockMod.tickAmount % 4 == 0) {
+ if (ToggleCommand.blazeToggled && Utils.inDungeons && world != null) {
+ List<Entity> entities = world.getLoadedEntityList();
+ int highestHealth = 0;
+ highestBlaze = null;
+ int lowestHealth = 99999999;
+ lowestBlaze = null;
+
+ for (Entity entity : entities) {
+ if (entity.getName().contains("Blaze") && entity.getName().contains("/")) {
+ String blazeName = StringUtils.stripControlCodes(entity.getName());
+ try {
+ int health = Integer.parseInt(blazeName.substring(blazeName.indexOf("/") + 1, blazeName.length() - 1));
+ if (health > highestHealth) {
+ highestHealth = health;
+ highestBlaze = entity;
+ }
+ if (health < lowestHealth) {
+ lowestHealth = health;
+ lowestBlaze = entity;
+ }
+ } catch (NumberFormatException ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void onWorldRender(RenderWorldLastEvent event) {
+ if (ToggleCommand.blazeToggled && Utils.inDungeons) {
+ if (lowestBlaze != null) {
+ BlockPos stringPos = new BlockPos(lowestBlaze.posX, lowestBlaze.posY + 1, lowestBlaze.posZ);
+ Utils.draw3DString(stringPos, EnumChatFormatting.BOLD + "Smallest", LOWEST_BLAZE_COLOUR, event.partialTicks);
+ AxisAlignedBB aabb = new AxisAlignedBB(lowestBlaze.posX - 0.5, lowestBlaze.posY - 2, lowestBlaze.posZ - 0.5, lowestBlaze.posX + 0.5, lowestBlaze.posY, lowestBlaze.posZ + 0.5);
+ Utils.draw3DBox(aabb, LOWEST_BLAZE_COLOUR, event.partialTicks);
+ }
+ if (highestBlaze != null) {
+ BlockPos stringPos = new BlockPos(highestBlaze.posX, highestBlaze.posY + 1, highestBlaze.posZ);
+ Utils.draw3DString(stringPos, EnumChatFormatting.BOLD + "Biggest", HIGHEST_BLAZE_COLOUR, event.partialTicks);
+ AxisAlignedBB aabb = new AxisAlignedBB(highestBlaze.posX - 0.5, highestBlaze.posY - 2, highestBlaze.posZ - 0.5, highestBlaze.posX + 0.5, highestBlaze.posY, highestBlaze.posZ + 0.5);
+ Utils.draw3DBox(aabb, HIGHEST_BLAZE_COLOUR, event.partialTicks);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/me/Danker/features/puzzlesolvers/BlockPlacingFlowers.java b/src/main/java/me/Danker/features/puzzlesolvers/BlockPlacingFlowers.java
new file mode 100644
index 0000000..fe89fef
--- /dev/null
+++ b/src/main/java/me/Danker/features/puzzlesolvers/BlockPlacingFlowers.java
@@ -0,0 +1,44 @@
+package me.Danker.features.puzzlesolvers;
+
+import me.Danker.commands.ToggleCommand;
+import me.Danker.utils.Utils;
+import net.minecraft.block.Block;
+import net.minecraft.client.Minecraft;
+import net.minecraft.init.Blocks;
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.event.entity.player.PlayerInteractEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+public class BlockPlacingFlowers {
+
+ @SubscribeEvent
+ public void onInteract(PlayerInteractEvent event) {
+ if (!Utils.inSkyblock || Minecraft.getMinecraft().thePlayer != event.entityPlayer) return;
+ ItemStack item = event.entityPlayer.getHeldItem();
+ if (item == null) return;
+
+ if (event.action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) {
+ Block block = Minecraft.getMinecraft().theWorld.getBlockState(event.pos).getBlock();
+
+ ArrayList<Block> flowerPlaceable = new ArrayList<>(Arrays.asList(
+ Blocks.grass,
+ Blocks.dirt,
+ Blocks.flower_pot,
+ Blocks.tallgrass,
+ Blocks.double_plant
+ ));
+ if (flowerPlaceable.contains(block)) {
+ if (ToggleCommand.flowerWeaponsToggled && item.getDisplayName().contains("Flower of Truth")) {
+ event.setCanceled(true);
+ }
+ if (ToggleCommand.flowerWeaponsToggled && item.getDisplayName().contains("Spirit Sceptre")) {
+ event.setCanceled(true);
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/me/Danker/features/puzzlesolvers/BlockWrongTerminalClicks.java b/src/main/java/me/Danker/features/puzzlesolvers/BlockWrongTerminalClicks.java
new file mode 100644
index 0000000..e967623
--- /dev/null
+++ b/src/main/java/me/Danker/features/puzzlesolvers/BlockWrongTerminalClicks.java
@@ -0,0 +1,112 @@
+package me.Danker.features.puzzlesolvers;
+
+import me.Danker.commands.ToggleCommand;
+import me.Danker.events.ChestSlotClickedEvent;
+import me.Danker.utils.Utils;
+import net.minecraft.init.Blocks;
+import net.minecraft.inventory.IInventory;
+import net.minecraft.inventory.Slot;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.StringUtils;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import org.lwjgl.input.Keyboard;
+
+public class BlockWrongTerminalClicks {
+
+ @SubscribeEvent
+ public void onSlotClick(ChestSlotClickedEvent event) {
+ if (ToggleCommand.blockWrongTerminalClicksToggled && Utils.inDungeons) {
+ IInventory inventory = event.inventory;
+ String inventoryName = event.inventoryName;
+ Slot slot = event.slot;
+ ItemStack item = event.item;
+ boolean shouldCancel = false;
+
+ if (item == null) return;
+
+ //most of these are extra but who cares
+
+ switch (inventoryName) {
+ case "Correct all the panes!":
+ shouldCancel = !StringUtils.stripControlCodes(item.getDisplayName()).startsWith("Off");
+ break;
+ case "Navigate the maze!":
+ if (item.getItem() != Item.getItemFromBlock(Blocks.stained_glass_pane)) {
+ shouldCancel = true;
+ break;
+ }
+
+ if (item.getItemDamage() != 0) {
+ shouldCancel = true;
+ break;
+ }
+
+ boolean isValid = false;
+
+ int slotIndex = slot.getSlotIndex();
+
+ if (slotIndex % 9 != 8 && slotIndex != 53) {
+ ItemStack itemStack = inventory.getStackInSlot(slotIndex + 1);
+ if (itemStack != null && itemStack.getItemDamage() == 5) isValid = true;
+ }
+
+ if (!isValid && slotIndex % 9 != 0 && slotIndex != 0) {
+ ItemStack itemStack = inventory.getStackInSlot(slotIndex - 1);
+ if (itemStack != null && itemStack.getItemDamage() == 5) isValid = true;
+ }
+
+ if (!isValid && slotIndex <= 44) {
+ ItemStack itemStack = inventory.getStackInSlot(slotIndex + 9);
+ if (itemStack != null && itemStack.getItemDamage() == 5) isValid = true;
+ }
+
+ if (!isValid && slotIndex >= 9) {
+ ItemStack itemStack = inventory.getStackInSlot(slotIndex - 9);
+ if (itemStack != null && itemStack.getItemDamage() == 5) isValid = true;
+ }
+
+ shouldCancel = !isValid;
+
+ break;
+ case "Click in order!":
+
+ if (slot.getSlotIndex() > 35) {
+ break;
+ }
+
+ if ((item.getItem() != Item.getItemFromBlock(Blocks.stained_glass_pane))) {
+ shouldCancel = true;
+ break;
+ }
+ if (item.getItemDamage() != 14) {
+ shouldCancel = true;
+ break;
+ }
+ int needed = ClickInOrderSolver.terminalNumberNeeded[0];
+ if (needed == 0) break;
+ shouldCancel = needed != -1 && item.stackSize != needed;
+ break;
+ }
+
+ if (!shouldCancel) {
+ if (inventoryName.startsWith("What starts with:")) {
+ char letter = inventoryName.charAt(inventoryName.indexOf("'") + 1);
+ shouldCancel = !(StringUtils.stripControlCodes(item.getDisplayName()).charAt(0) == letter);
+ } else if (inventoryName.startsWith("Select all the")) {
+ if (SelectAllColourSolver.terminalColorNeeded == null) return;
+ String itemName = StringUtils.stripControlCodes(item.getDisplayName()).toUpperCase();
+ shouldCancel = !(itemName.contains(SelectAllColourSolver.terminalColorNeeded) ||
+ (SelectAllColourSolver.terminalColorNeeded.equals("SILVER") && itemName.contains("LIGHT GRAY")) ||
+ (SelectAllColourSolver.terminalColorNeeded.equals("WHITE") && (itemName.equals("WOOL") || itemName.equals("BONE MEAL"))) ||
+ (SelectAllColourSolver.terminalColorNeeded.equals("BLACK") && itemName.equals("INK SACK")) ||
+ (SelectAllColourSolver.terminalColorNeeded.equals("BLUE") && itemName.equals("LAPIS LAZULI")) ||
+ (SelectAllColourSolver.terminalColorNeeded.equals("BROWN") && itemName.equals("COCOA BEANS")));
+ }
+ }
+
+ event.setCanceled(shouldCancel && !Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) && !Keyboard.isKeyDown(Keyboard.KEY_RCONTROL));
+ }
+ }
+
+}
diff --git a/src/main/java/me/Danker/features/puzzlesolvers/BoulderSolver.java b/src/main/java/me/Danker/features/puzzlesolvers/BoulderSolver.java
new file mode 100644
index 0000000..0089038
--- /dev/null
+++ b/src/main/java/me/Danker/features/puzzlesolvers/BoulderSolver.java
@@ -0,0 +1,188 @@
+package me.Danker.features.puzzlesolvers;
+
+import me.Danker.DankersSkyblockMod;
+import me.Danker.commands.ToggleCommand;
+import me.Danker.utils.BoulderUtils;
+import me.Danker.utils.Utils;
+import net.minecraft.block.Block;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.EntityPlayerSP;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.world.World;
+import net.minecraftforge.client.event.RenderWorldLastEvent;
+import net.minecraftforge.event.entity.player.PlayerInteractEvent;
+import net.minecraftforge.event.world.WorldEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class BoulderSolver {
+
+ static boolean prevInBoulderRoom = false;
+ static boolean inBoulderRoom = false;
+ static BlockPos chest = null;
+ static String boulderRoomDirection = null;
+ public static List<int[]> route = new ArrayList<>();
+ static int currentStep = 0;
+ public static int BOULDER_COLOUR;
+ public static int BOULDER_ARROW_COLOUR;
+
+ @SubscribeEvent
+ public void onWorldChange(WorldEvent.Load event) {
+ reset();
+ }
+
+ @SubscribeEvent
+ public void onTick(TickEvent.ClientTickEvent event) {
+ if (event.phase != TickEvent.Phase.START) return;
+
+ Minecraft mc = Minecraft.getMinecraft();
+ EntityPlayerSP player = mc.thePlayer;
+ World world = mc.theWorld;
+ if (DankersSkyblockMod.tickAmount % 20 == 0) {
+ if (ToggleCommand.boulderToggled && Utils.inDungeons && world != null && player != null) {
+ // multi thread block checking
+ new Thread(() -> {
+ prevInBoulderRoom = inBoulderRoom;
+ int quartzBlocksFound = 0;
+ int barriersFound = 0;
+ BlockPos plusPlusQuartz = null;
+ BlockPos minusMinusQuartz = null;
+ Iterable<BlockPos> blocks = BlockPos.getAllInBox(new BlockPos(player.posX - 25, 68, player.posZ - 25), new BlockPos(player.posX + 25, 68, player.posZ + 25));
+ // Detect boulder room
+ for (BlockPos blockPos : blocks) {
+ if (world.getBlockState(blockPos).getBlock() == Blocks.quartz_block) {
+ quartzBlocksFound++;
+ if (plusPlusQuartz == null || (blockPos.getX() >= plusPlusQuartz.getX() && blockPos.getZ() >= plusPlusQuartz.getZ())) {
+ plusPlusQuartz = blockPos;
+ }
+ if (minusMinusQuartz == null || (blockPos.getX() <= minusMinusQuartz.getX() && blockPos.getZ() <= minusMinusQuartz.getZ())) {
+ minusMinusQuartz = blockPos;
+ }
+ if (quartzBlocksFound == 8) {
+ break;
+ }
+ } else if (world.getBlockState(blockPos).getBlock() == Blocks.barrier) {
+ barriersFound++;
+ }
+ }
+
+ if (quartzBlocksFound == 8 && barriersFound >= 350) {
+ inBoulderRoom = true;
+ if (!prevInBoulderRoom) {
+ // Get boulder locations
+ char[][] board = new char[7][7];
+ for (int x = plusPlusQuartz.getX() - 1, iterationX = 0; iterationX < 7; x -= 3, iterationX++) {
+ for (int z = plusPlusQuartz.getZ() - 1, iterationZ = 0; iterationZ < 7; z -= 3, iterationZ++) {
+ BlockPos boulderPos = new BlockPos(x, 66, z);
+ if (world.getBlockState(boulderPos).getBlock() == Blocks.planks) {
+ board[iterationX][iterationZ] = 'X';
+ }
+ }
+ }
+
+ // Detect rotation of room
+ BlockPos northChest = minusMinusQuartz.add(11, -2, -2);
+ BlockPos eastChest = plusPlusQuartz.add(2, -2, -11);
+ BlockPos southChest = plusPlusQuartz.add(-11, -2, 2);
+ BlockPos westChest = minusMinusQuartz.add(-2, -2, 11);
+ if (world.getBlockState(northChest).getBlock() == Blocks.chest) {
+ boulderRoomDirection = "north";
+ chest = northChest;
+ board = BoulderUtils.flipVertically(BoulderUtils.rotateClockwise(board));
+ } else if (world.getBlockState(eastChest).getBlock() == Blocks.chest) {
+ boulderRoomDirection = "east";
+ chest = eastChest;
+ board = BoulderUtils.flipHorizontally(board);
+ } else if (world.getBlockState(southChest).getBlock() == Blocks.chest) {
+ boulderRoomDirection = "south";
+ chest = southChest;
+ board = BoulderUtils.flipHorizontally(BoulderUtils.rotateClockwise(board));
+ } else if (world.getBlockState(westChest).getBlock() == Blocks.chest) {
+ boulderRoomDirection = "west";
+ chest = westChest;
+ board = BoulderUtils.flipVertically(board);
+ } else {
+ player.addChatMessage(new ChatComponentText(DankersSkyblockMod.ERROR_COLOUR + "Could not determine orientation of boulder room."));
+ return;
+ }
+ board = BoulderUtils.removeFirstRow(board);
+ if (BoulderUtils.hasOpenPath(board)) return;
+
+ long startTime = System.currentTimeMillis();
+ reset();
+ int length = BoulderUtils.findSolution(board, 0, route);
+ long endTime = System.currentTimeMillis();
+ System.out.println("Time elapsed: " + (endTime - startTime) + "ms, " + BoulderUtils.iterations + " iterations.");
+ if (length == 10) {
+ player.addChatMessage(new ChatComponentText(DankersSkyblockMod.ERROR_COLOUR + "No solution to puzzle found, most likely puzzle failed."));
+ } else {
+ System.out.println("Solved " + boulderRoomDirection + " facing boulder room in " + length + " steps. Path:");
+ for (int[] block : route) {
+ System.out.println(Arrays.toString(block));
+ }
+ }
+ }
+ } else {
+ chest = null;
+ boulderRoomDirection = null;
+ inBoulderRoom = false;
+ }
+ }).start();
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void onWorldRender(RenderWorldLastEvent event) {
+ if (ToggleCommand.boulderToggled && Utils.inDungeons && route.size() > 0 && currentStep < route.size() && chest != null) {
+ int[] currentBlockArray = route.get(currentStep);
+ AxisAlignedBB currentBoulder = BoulderUtils.getBoulder(currentBlockArray[0], currentBlockArray[1], chest, boulderRoomDirection);
+ if (currentBoulder == null) return;
+ Utils.drawFilled3DBox(currentBoulder, BOULDER_COLOUR, true, false, event.partialTicks);
+ char direction;
+ switch (currentBlockArray[2]) {
+ case 1:
+ direction = 'u';
+ break;
+ case 2:
+ direction = 'd';
+ break;
+ case 3:
+ direction = 'l';
+ break;
+ case 4:
+ direction = 'r';
+ break;
+ default:
+ return;
+ }
+ BoulderUtils.drawArrow(currentBoulder, boulderRoomDirection, direction, 0xFF000000 + BOULDER_ARROW_COLOUR, event.partialTicks);
+ }
+ }
+
+ @SubscribeEvent
+ public void onInteract(PlayerInteractEvent event) {
+ if (Minecraft.getMinecraft().thePlayer != event.entityPlayer || !inBoulderRoom || !ToggleCommand.boulderToggled) return;
+
+ if (event.action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) {
+ Block block = Minecraft.getMinecraft().theWorld.getBlockState(event.pos).getBlock();
+ if (block == Blocks.stone_button) currentStep++;
+ }
+ }
+
+ static void reset() {
+ route.clear();
+ currentStep = 0;
+ BoulderUtils.seenBoardStates.clear();
+ BoulderUtils.iterations = 0;
+ BoulderUtils.fastestSolution = 10;
+ }
+
+}
diff --git a/src/main/java/me/Danker/features/puzzlesolvers/ChronomatronSolver.java b/src/main/java/me/Danker/features/puzzlesolvers/ChronomatronSolver.java
new file mode 100644
index 0000000..7bbd25a
--- /dev/null
+++ b/src/main/java/me/Danker/features/puzzlesolvers/ChronomatronSolver.java
@@ -0,0 +1,114 @@
+package me.Danker.features.puzzlesolvers;
+
+import me.Danker.commands.ToggleCommand;
+import me.Danker.events.ChestSlotClickedEvent;
+import me.Danker.events.GuiChestBackgroundDrawnEvent;
+import me.Danker.handlers.TextRenderer;
+import me.Danker.utils.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.init.Blocks;
+import net.minecraft.inventory.IInventory;
+import net.minecraft.inventory.Slot;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.StringUtils;
+import net.minecraftforge.client.event.GuiOpenEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import org.lwjgl.input.Keyboard;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ChronomatronSolver {
+
+ static int lastChronomatronRound = 0;
+ static List<String> chronomatronPattern = new ArrayList<>();
+ static int chronomatronMouseClicks = 0;
+ public static int CHRONOMATRON_NEXT;
+ public static int CHRONOMATRON_NEXT_TO_NEXT;
+
+ @SubscribeEvent
+ public void onSlotClick(ChestSlotClickedEvent event) {
+ if (ToggleCommand.chronomatronToggled && event.inventoryName.startsWith("Chronomatron (")) {
+ IInventory inventory = event.inventory;
+ ItemStack item = event.item;
+ if (item == null) {
+ if (event.isCancelable() && !Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) && !Keyboard.isKeyDown(Keyboard.KEY_RCONTROL))
+ event.setCanceled(true);
+ return;
+ }
+ if (inventory.getStackInSlot(49).getDisplayName().startsWith("§7Timer: §a") && (item.getItem() == Item.getItemFromBlock(Blocks.stained_glass) || item.getItem() == Item.getItemFromBlock(Blocks.stained_hardened_clay))) {
+ if (chronomatronPattern.size() > chronomatronMouseClicks && !item.getDisplayName().equals(chronomatronPattern.get(chronomatronMouseClicks))) {
+ if (event.isCancelable() && !Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) && !Keyboard.isKeyDown(Keyboard.KEY_RCONTROL))
+ event.setCanceled(true);
+ return;
+ }
+ chronomatronMouseClicks++;
+ } else if (inventory.getStackInSlot(49).getDisplayName().startsWith("§aRemember the pattern!")) {
+ if (event.isCancelable()) event.setCanceled(true);
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void onGuiRender(GuiChestBackgroundDrawnEvent event) {
+ if (ToggleCommand.chronomatronToggled && event.displayName.startsWith("Chronomatron (")) {
+ int chestSize = event.chestSize;
+ List<Slot> invSlots = event.slots;
+ if (invSlots.size() > 48 && invSlots.get(49).getStack() != null) {
+ if (invSlots.get(49).getStack().getDisplayName().startsWith("§7Timer: §a") && invSlots.get(4).getStack() != null) {
+ int round = invSlots.get(4).getStack().stackSize;
+ int timerSeconds = Integer.parseInt(StringUtils.stripControlCodes(invSlots.get(49).getStack().getDisplayName()).replaceAll("[^\\d]", ""));
+ if (round != lastChronomatronRound && timerSeconds == round + 2) {
+ lastChronomatronRound = round;
+ for (int i = 10; i <= 43; i++) {
+ ItemStack stack = invSlots.get(i).getStack();
+ if (stack == null) continue;
+ if (stack.getItem() == Item.getItemFromBlock(Blocks.stained_hardened_clay)) {
+ chronomatronPattern.add(stack.getDisplayName());
+ break;
+ }
+ }
+ }
+ if (chronomatronMouseClicks < chronomatronPattern.size()) {
+ for (int i = 10; i <= 43; i++) {
+ ItemStack glass = invSlots.get(i).getStack();
+ if (glass == null) continue;
+
+ Slot glassSlot = invSlots.get(i);
+
+ if (chronomatronMouseClicks + 1 < chronomatronPattern.size()) {
+ if (chronomatronPattern.get(chronomatronMouseClicks).equals(chronomatronPattern.get(chronomatronMouseClicks + 1))) {
+ if (glass.getDisplayName().equals(chronomatronPattern.get(chronomatronMouseClicks))) {
+ Utils.drawOnSlot(chestSize, glassSlot.xDisplayPosition, glassSlot.yDisplayPosition, CHRONOMATRON_NEXT + 0xE5000000);
+ }
+ } else if (glass.getDisplayName().equals(chronomatronPattern.get(chronomatronMouseClicks))) {
+ Utils.drawOnSlot(chestSize, glassSlot.xDisplayPosition, glassSlot.yDisplayPosition, CHRONOMATRON_NEXT + 0xE5000000);
+ } else if (glass.getDisplayName().equals(chronomatronPattern.get(chronomatronMouseClicks + 1))) {
+ Utils.drawOnSlot(chestSize, glassSlot.xDisplayPosition, glassSlot.yDisplayPosition, CHRONOMATRON_NEXT_TO_NEXT + 0XBE000000);
+ }
+ } else if (glass.getDisplayName().equals(chronomatronPattern.get(chronomatronMouseClicks))) {
+ Utils.drawOnSlot(chestSize, glassSlot.xDisplayPosition, glassSlot.yDisplayPosition, CHRONOMATRON_NEXT + 0xE5000000);
+ }
+ }
+ }
+ } else if (invSlots.get(49).getStack().getDisplayName().equals("§aRemember the pattern!")) {
+ chronomatronMouseClicks = 0;
+ }
+ }
+ Minecraft mc = Minecraft.getMinecraft();
+ ScaledResolution sr = new ScaledResolution(mc);
+ int guiLeft = (sr.getScaledWidth() - 176) / 2;
+ new TextRenderer(mc, String.join("\n", chronomatronPattern), (int) (guiLeft * 0.8), 10, 1);
+ }
+ }
+
+ @SubscribeEvent
+ public void onGuiOpen(GuiOpenEvent event) {
+ lastChronomatronRound = 0;
+ chronomatronPattern.clear();
+ chronomatronMouseClicks = 0;
+ }
+
+}
diff --git a/src/main/java/me/Danker/features/puzzlesolvers/ClickInOrderSolver.java b/src/main/java/me/Danker/features/puzzlesolvers/ClickInOrderSolver.java
new file mode 100644
index 0000000..e503b37
--- /dev/null
+++ b/src/main/java/me/Danker/features/puzzlesolvers/ClickInOrderSolver.java
@@ -0,0 +1,107 @@
+package me.Danker.features.puzzlesolvers;
+
+import me.Danker.commands.ToggleCommand;
+import me.Danker.events.GuiChestBackgroundDrawnEvent;
+import me.Danker.utils.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.EntityPlayerSP;
+import net.minecraft.client.gui.inventory.GuiChest;
+import net.minecraft.init.Blocks;
+import net.minecraft.inventory.ContainerChest;
+import net.minecraft.inventory.IInventory;
+import net.minecraft.inventory.Slot;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.client.event.GuiOpenEvent;
+import net.minecraftforge.event.entity.player.ItemTooltipEvent;
+import net.minecraftforge.fml.common.eventhandler.EventPriority;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
+
+import java.util.List;
+
+public class ClickInOrderSolver {
+
+ static Slot[] clickInOrderSlots = new Slot[36];
+ static int[] terminalNumberNeeded = new int[4];
+ public static int CLICK_IN_ORDER_NEXT;
+ public static int CLICK_IN_ORDER_NEXT_TO_NEXT;
+
+ @SubscribeEvent(priority = EventPriority.LOW)
+ public void onTooltipLow(ItemTooltipEvent event) {
+ if (!Utils.inSkyblock) return;
+ if (event.toolTip == null) return;
+
+ Minecraft mc = Minecraft.getMinecraft();
+ EntityPlayerSP player = mc.thePlayer;
+
+ if (mc.currentScreen instanceof GuiChest) {
+ ContainerChest chest = (ContainerChest) player.openContainer;
+ IInventory inv = chest.getLowerChestInventory();
+ String chestName = inv.getDisplayName().getUnformattedText();
+
+ if (ToggleCommand.clickInOrderToggled && chestName.equals("Click in order!")) {
+ event.toolTip.clear();
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void onTick(TickEvent.ClientTickEvent event) {
+ if (event.phase != TickEvent.Phase.START) return;
+
+ Minecraft mc = Minecraft.getMinecraft();
+ EntityPlayerSP player = mc.thePlayer;
+ if (mc.currentScreen instanceof GuiChest) {
+ if (player == null) return;
+ ContainerChest chest = (ContainerChest) player.openContainer;
+ List<Slot> invSlots = ((GuiChest) mc.currentScreen).inventorySlots.inventorySlots;
+ String chestName = chest.getLowerChestInventory().getDisplayName().getUnformattedText().trim();
+
+ if (ToggleCommand.clickInOrderToggled && chestName.equals("Click in order!")) {
+ if (terminalNumberNeeded[0] == 0) terminalNumberNeeded[0] = 15;
+ if (terminalNumberNeeded[2] == 0) terminalNumberNeeded[2] = 15;
+ for (int i = 10; i <= 25; i++) {
+ if (i == 17 || i == 18) continue;
+ ItemStack prevStack = invSlots.get(terminalNumberNeeded[1]).getStack();
+ if (prevStack == null) terminalNumberNeeded[0] = 15;
+ else if (prevStack.getItem() != Item.getItemFromBlock(Blocks.stained_glass_pane))
+ terminalNumberNeeded[0] = 15;
+ else if (prevStack.getItemDamage() == 5) terminalNumberNeeded[0] = 15;
+
+ ItemStack itemStack = invSlots.get(i).getStack();
+ if (itemStack == null) continue;
+ if (itemStack.getItem() != Item.getItemFromBlock(Blocks.stained_glass_pane)) continue;
+ if (itemStack.getItemDamage() != 14) continue;
+ if (itemStack.stackSize < terminalNumberNeeded[0]) {
+ terminalNumberNeeded[0] = itemStack.stackSize;
+ terminalNumberNeeded[1] = i;
+ } else if (itemStack.stackSize == terminalNumberNeeded[0] + 1) {
+ terminalNumberNeeded[2] = itemStack.stackSize;
+ terminalNumberNeeded[3] = i;
+ }
+ }
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void onGuiRender(GuiChestBackgroundDrawnEvent event) {
+ if (ToggleCommand.clickInOrderToggled && event.displayName.equals("Click in order!")) {
+ int chestSize = event.chestSize;
+ List<Slot> invSlots = event.slots;
+ Slot slot = invSlots.get(terminalNumberNeeded[1]);
+ Utils.drawOnSlot(chestSize, slot.xDisplayPosition, slot.yDisplayPosition, CLICK_IN_ORDER_NEXT + 0xFF000000);
+ Slot nextSlot = invSlots.get(terminalNumberNeeded[3]);
+ if (nextSlot != slot && nextSlot.getSlotIndex() != 0) {
+ Utils.drawOnSlot(chestSize, nextSlot.xDisplayPosition, nextSlot.yDisplayPosition, CLICK_IN_ORDER_NEXT_TO_NEXT + 0xFF000000);
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void onGuiOpen(GuiOpenEvent event) {
+ terminalNumberNeeded = new int[4];
+ }
+
+}
diff --git a/src/main/java/me/Danker/features/puzzlesolvers/CreeperSolver.java b/src/main/java/me/Danker/features/puzzlesolvers/CreeperSolver.java
new file mode 100644
index 0000000..7ff7e7a
--- /dev/null
+++ b/src/main/java/me/Danker/features/puzzlesolvers/CreeperSolver.java
@@ -0,0 +1,86 @@
+package me.Danker.features.puzzlesolvers;
+
+import me.Danker.DankersSkyblockMod;
+import me.Danker.commands.ToggleCommand;
+import me.Danker.utils.Utils;
+import net.minecraft.block.Block;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.EntityPlayerSP;
+import net.minecraft.entity.monster.EntityCreeper;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.Vec3;
+import net.minecraft.world.World;
+import net.minecraftforge.client.event.RenderWorldLastEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CreeperSolver {
+
+ // Among Us colours
+ static final int[] CREEPER_COLOURS = {0x50EF39, 0xC51111, 0x132ED1, 0x117F2D, 0xED54BA, 0xEF7D0D, 0xF5F557, 0xD6E0F0, 0x6B2FBB, 0x39FEDC};
+ static boolean drawCreeperLines = false;
+ static Vec3 creeperLocation = new Vec3(0, 0, 0);
+ static List<Vec3[]> creeperLines = new ArrayList<>();
+
+ @SubscribeEvent
+ public void onTick(TickEvent.ClientTickEvent event) {
+ if (event.phase != TickEvent.Phase.START) return;
+
+ Minecraft mc = Minecraft.getMinecraft();
+ World world = mc.theWorld;
+ EntityPlayerSP player = mc.thePlayer;
+ if (DankersSkyblockMod.tickAmount % 20 == 0) {
+ if (ToggleCommand.creeperToggled && Utils.inDungeons && world != null && player != null) {
+ double x = player.posX;
+ double y = player.posY;
+ double z = player.posZ;
+ // Find creepers nearby
+ AxisAlignedBB creeperScan = new AxisAlignedBB(x - 14, y - 8, z - 13, x + 14, y + 8, z + 13); // 28x16x26 cube
+ List<EntityCreeper> creepers = world.getEntitiesWithinAABB(EntityCreeper.class, creeperScan);
+ // Check if creeper is nearby
+ if (creepers.size() > 0 && !creepers.get(0).isInvisible()) { // Don't show Wither Cloak creepers
+ EntityCreeper creeper = creepers.get(0);
+ // Start creeper line drawings
+ creeperLines.clear();
+ if (!drawCreeperLines) creeperLocation = new Vec3(creeper.posX, creeper.posY + 1, creeper.posZ);
+ drawCreeperLines = true;
+ // Search for nearby sea lanterns and prismarine blocks
+ BlockPos point1 = new BlockPos(creeper.posX - 14, creeper.posY - 7, creeper.posZ - 13);
+ BlockPos point2 = new BlockPos(creeper.posX + 14, creeper.posY + 10, creeper.posZ + 13);
+ Iterable<BlockPos> blocks = BlockPos.getAllInBox(point1, point2);
+ for (BlockPos blockPos : blocks) {
+ Block block = world.getBlockState(blockPos).getBlock();
+ if (block == Blocks.sea_lantern || block == Blocks.prismarine) {
+ // Connect block to nearest block on opposite side
+ Vec3 startBlock = new Vec3(blockPos.getX() + 0.5, blockPos.getY() + 0.5, blockPos.getZ() + 0.5);
+ BlockPos oppositeBlock = Utils.getFirstBlockPosAfterVectors(mc, startBlock, creeperLocation, 10, 20);
+ BlockPos endBlock = Utils.getNearbyBlock(mc, oppositeBlock, Blocks.sea_lantern, Blocks.prismarine);
+ if (endBlock != null && startBlock.yCoord > 68 && endBlock.getY() > 68) { // Don't create line underground
+ // Add to list for drawing
+ Vec3[] insertArray = {startBlock, new Vec3(endBlock.getX() + 0.5, endBlock.getY() + 0.5, endBlock.getZ() + 0.5)};
+ creeperLines.add(insertArray);
+ }
+ }
+ }
+ } else {
+ drawCreeperLines = false;
+ }
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void onWorldRender(RenderWorldLastEvent event) {
+ if (ToggleCommand.creeperToggled && drawCreeperLines && !creeperLines.isEmpty()) {
+ for (int i = 0; i < creeperLines.size(); i++) {
+ Utils.draw3DLine(creeperLines.get(i)[0], creeperLines.get(i)[1], CREEPER_COLOURS[i % 10], 2, true, event.partialTicks);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/me/Danker/features/puzzlesolvers/LividSolver.java b/src/main/java/me/Danker/features/puzzlesolvers/LividSolver.java
new file mode 100644
index 0000000..b537198
--- /dev/null
+++ b/src/main/java/me/Danker/features/puzzlesolvers/LividSolver.java
@@ -0,0 +1,89 @@
+package me.Danker.features.puzzlesolvers;
+
+import me.Danker.DankersSkyblockMod;
+import me.Danker.commands.MoveCommand;
+import me.Danker.commands.ScaleCommand;
+import me.Danker.commands.ToggleCommand;
+import me.Danker.events.RenderOverlay;
+import me.Danker.handlers.ScoreboardHandler;
+import me.Danker.handlers.TextRenderer;
+import me.Danker.utils.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.item.EntityArmorStand;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.world.World;
+import net.minecraftforge.client.event.RenderLivingEvent;
+import net.minecraftforge.event.world.WorldEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class LividSolver {
+
+ static boolean foundLivid = false;
+ static Entity livid = null;
+
+ @SubscribeEvent
+ public void onWorldChange(WorldEvent.Load event) {
+ foundLivid = false;
+ livid = null;
+ }
+
+ @SubscribeEvent
+ public void onTick(TickEvent.ClientTickEvent event) {
+ if (event.phase != TickEvent.Phase.START) return;
+
+ World world = Minecraft.getMinecraft().theWorld;
+ if (DankersSkyblockMod.tickAmount % 20 == 0) {
+ if (ToggleCommand.lividSolverToggled && Utils.inDungeons && !foundLivid && world != null) {
+ boolean inF5 = false;
+
+ List<String> scoreboard = ScoreboardHandler.getSidebarLines();
+ for (String s : scoreboard) {
+ String sCleaned = ScoreboardHandler.cleanSB(s);
+ if (sCleaned.contains("The Catacombs (F5)")) {
+ inF5 = true;
+ break;
+ }
+ }
+
+ if (inF5) {
+ List<Entity> loadedLivids = new ArrayList<>();
+ List<Entity> entities = world.getLoadedEntityList();
+ for (Entity entity : entities) {
+ String name = entity.getName();
+ if (name.contains("Livid") && name.length() > 5 && name.charAt(1) == name.charAt(5) && !loadedLivids.contains(entity)) {
+ loadedLivids.add(entity);
+ }
+ }
+ if (loadedLivids.size() > 8) {
+ livid = loadedLivids.get(0);
+ foundLivid = true;
+ }
+ }
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void renderPlayerInfo(RenderOverlay event) {
+ if (ToggleCommand.lividSolverToggled && foundLivid && livid != null) {
+ new TextRenderer(Minecraft.getMinecraft(), livid.getName().replace("" + EnumChatFormatting.BOLD, ""), MoveCommand.lividHpXY[0], MoveCommand.lividHpXY[1], ScaleCommand.lividHpScale);
+ }
+ }
+
+ @SubscribeEvent
+ public void onRenderEntity(RenderLivingEvent.Pre event) {
+ Entity entity = event.entity;
+ String name = entity.getName();
+ if (entity instanceof EntityArmorStand) {
+ if (ToggleCommand.lividSolverToggled && !entity.isEntityEqual(livid) && name.contains("Livid") && name.length() > 5 && name.charAt(1) == name.charAt(5)) {
+ event.setCanceled(true);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/me/Danker/features/puzzlesolvers/SelectAllColourSolver.java b/src/main/java/me/Danker/features/puzzlesolvers/SelectAllColourSolver.java
new file mode 100644
index 0000000..cce89d2
--- /dev/null
+++ b/src/main/java/me/Danker/features/puzzlesolvers/SelectAllColourSolver.java
@@ -0,0 +1,59 @@
+package me.Danker.features.puzzlesolvers;
+
+import me.Danker.commands.ToggleCommand;
+import me.Danker.events.GuiChestBackgroundDrawnEvent;
+import me.Danker.utils.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.inventory.Slot;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.StringUtils;
+import net.minecraftforge.client.event.GuiOpenEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class SelectAllColourSolver {
+
+ static Pattern selectAllTerminalPattern = Pattern.compile("[A-Z]{2,}");
+ static String terminalColorNeeded;
+
+ @SubscribeEvent
+ public void onGuiRender(GuiChestBackgroundDrawnEvent event) {
+ String displayName = event.displayName;
+ if (ToggleCommand.selectAllToggled && Utils.inDungeons && displayName.startsWith("Select all the")) {
+ String colour;
+ List<String> colourParts = new ArrayList<>();
+ Matcher colourMatcher = selectAllTerminalPattern.matcher(displayName);
+ while (colourMatcher.find()) {
+ colourParts.add(colourMatcher.group());
+ }
+ colour = String.join(" ", colourParts);
+ terminalColorNeeded = colour;
+
+ for (Slot slot : event.slots) {
+ if (slot.inventory == Minecraft.getMinecraft().thePlayer.inventory) continue;
+ ItemStack item = slot.getStack();
+ if (item == null) continue;
+ if (item.isItemEnchanted()) continue;
+ String itemName = StringUtils.stripControlCodes(item.getDisplayName()).toUpperCase();
+ if (itemName.contains(terminalColorNeeded) ||
+ (terminalColorNeeded.equals("SILVER") && itemName.contains("LIGHT GRAY")) ||
+ (terminalColorNeeded.equals("WHITE") && (itemName.equals("WOOL") || itemName.equals("BONE MEAL"))) ||
+ (terminalColorNeeded.equals("BLACK") && itemName.equals("INK SACK")) ||
+ (terminalColorNeeded.equals("BLUE") && itemName.equals("LAPIS LAZULI")) ||
+ (terminalColorNeeded.equals("BROWN") && itemName.equals("COCOA BEANS"))) {
+ Utils.drawOnSlot(event.chestSize, slot.xDisplayPosition, slot.yDisplayPosition, 0xBF40FF40);
+ }
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void onGuiOpen(GuiOpenEvent event) {
+ terminalColorNeeded = null;
+ }
+
+}
diff --git a/src/main/java/me/Danker/features/puzzlesolvers/StartsWithSolver.java b/src/main/java/me/Danker/features/puzzlesolvers/StartsWithSolver.java
new file mode 100644
index 0000000..8f15fa7
--- /dev/null
+++ b/src/main/java/me/Danker/features/puzzlesolvers/StartsWithSolver.java
@@ -0,0 +1,31 @@
+package me.Danker.features.puzzlesolvers;
+
+import me.Danker.commands.ToggleCommand;
+import me.Danker.events.GuiChestBackgroundDrawnEvent;
+import me.Danker.utils.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.inventory.Slot;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.StringUtils;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+
+public class StartsWithSolver {
+
+ @SubscribeEvent
+ public void onGuiRender(GuiChestBackgroundDrawnEvent event) {
+ String displayName = event.displayName;
+ if (ToggleCommand.startsWithToggled && Utils.inDungeons && displayName.startsWith("What starts with:")) {
+ char letter = displayName.charAt(displayName.indexOf("'") + 1);
+ for (Slot slot : event.slots) {
+ if (slot.inventory == Minecraft.getMinecraft().thePlayer.inventory) continue;
+ ItemStack item = slot.getStack();
+ if (item == null) continue;
+ if (item.isItemEnchanted()) continue;
+ if (StringUtils.stripControlCodes(item.getDisplayName()).charAt(0) == letter) {
+ Utils.drawOnSlot(event.chestSize, slot.xDisplayPosition, slot.yDisplayPosition, 0xBF40FF40);
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/me/Danker/features/puzzlesolvers/SuperpairsSolver.java b/src/main/java/me/Danker/features/puzzlesolvers/SuperpairsSolver.java
new file mode 100644
index 0000000..c6e1d76
--- /dev/null
+++ b/src/main/java/me/Danker/features/puzzlesolvers/SuperpairsSolver.java
@@ -0,0 +1,150 @@
+package me.Danker.features.puzzlesolvers;
+
+import me.Danker.commands.ToggleCommand;
+import me.Danker.events.GuiChestBackgroundDrawnEvent;
+import me.Danker.utils.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.EntityPlayerSP;
+import net.minecraft.client.gui.inventory.GuiChest;
+import net.minecraft.inventory.ContainerChest;
+import net.minecraft.inventory.IInventory;
+import net.minecraft.inventory.Slot;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.StringUtils;
+import net.minecraftforge.client.event.GuiOpenEvent;
+import net.minecraftforge.event.entity.player.ItemTooltipEvent;
+import net.minecraftforge.fml.common.eventhandler.EventPriority;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
+
+import java.awt.*;
+import java.util.List;
+import java.util.*;
+
+public class SuperpairsSolver {
+
+ static ItemStack[] experimentTableSlots = new ItemStack[54];
+
+ @SubscribeEvent(priority = EventPriority.HIGHEST)
+ public void onTooltip(ItemTooltipEvent event) {
+ if (!Utils.inSkyblock) return;
+ if (event.toolTip == null) return;
+
+ ItemStack item = event.itemStack;
+ Minecraft mc = Minecraft.getMinecraft();
+ EntityPlayerSP player = mc.thePlayer;
+
+ if (mc.currentScreen instanceof GuiChest) {
+ ContainerChest chest = (ContainerChest) player.openContainer;
+ IInventory inv = chest.getLowerChestInventory();
+ String chestName = inv.getDisplayName().getUnformattedText();
+
+ if (ToggleCommand.superpairsToggled && chestName.contains("Superpairs (")) {
+ if (Item.getIdFromItem(item.getItem()) != 95) return;
+ if (item.getDisplayName().contains("Click any button") || item.getDisplayName().contains("Click a second button") || item.getDisplayName().contains("Next button is instantly rewarded") || item.getDisplayName().contains("Stained Glass")) {
+ Slot slot = ((GuiChest) mc.currentScreen).getSlotUnderMouse();
+ ItemStack itemStack = experimentTableSlots[slot.getSlotIndex()];
+ if (itemStack == null) return;
+ String itemName = itemStack.getDisplayName();
+
+ if (event.toolTip.stream().anyMatch(x -> StringUtils.stripControlCodes(x).equals(StringUtils.stripControlCodes(itemName))))
+ return;
+ event.toolTip.removeIf(x -> {
+ x = StringUtils.stripControlCodes(x);
+ if (x.equals("minecraft:stained_glass")) return true;
+ return x.startsWith("NBT: ");
+ });
+ event.toolTip.add(itemName);
+ event.toolTip.add(itemStack.getItem().getRegistryName());
+ }
+
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void onTick(TickEvent.ClientTickEvent event) {
+ if (event.phase != TickEvent.Phase.START) return;
+
+ Minecraft mc = Minecraft.getMinecraft();
+ EntityPlayerSP player = mc.thePlayer;
+ if (mc.currentScreen instanceof GuiChest) {
+ if (player == null) return;
+ ContainerChest chest = (ContainerChest) player.openContainer;
+ List<Slot> invSlots = ((GuiChest) mc.currentScreen).inventorySlots.inventorySlots;
+ String chestName = chest.getLowerChestInventory().getDisplayName().getUnformattedText().trim();
+
+ if (ToggleCommand.superpairsToggled && chestName.startsWith("Superpairs (")) {
+ for (int i = 0; i < 53; i++) {
+ ItemStack itemStack = invSlots.get(i).getStack();
+ if (itemStack == null) continue;
+ String itemName = itemStack.getDisplayName();
+ if (Item.getIdFromItem(itemStack.getItem()) == 95 || Item.getIdFromItem(itemStack.getItem()) == 160) continue;
+ if (itemName.contains("Instant Find") || itemName.contains("Gained +")) continue;
+ if (itemName.contains("Enchanted Book")) {
+ itemName = itemStack.getTooltip(mc.thePlayer, false).get(3);
+ }
+ if (itemStack.stackSize > 1) {
+ itemName = itemStack.stackSize + " " + itemName;
+ }
+ if (experimentTableSlots[i] != null) continue;
+ experimentTableSlots[i] = itemStack.copy().setStackDisplayName(itemName);
+ }
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void onGuiRender(GuiChestBackgroundDrawnEvent event) {
+ if (ToggleCommand.superpairsToggled && event.displayName.contains("Superpairs (")) {
+ HashMap<String, HashSet<Integer>> matches = new HashMap<>();
+ for (int i = 0; i < 53; i++) {
+ ItemStack itemStack = experimentTableSlots[i];
+ if (itemStack == null) continue;
+
+ //Utils.renderItem(itemStack, x, y, -100);
+
+ String itemName = itemStack.getDisplayName();
+ String keyName = itemName + itemStack.getUnlocalizedName();
+ matches.computeIfAbsent(keyName, k -> new HashSet<>());
+ matches.get(keyName).add(i);
+ }
+
+ Color[] colors = {
+ new Color(255, 0, 0, 100),
+ new Color(0, 0, 255, 100),
+ new Color(100, 179, 113, 100),
+ new Color(255, 114, 255, 100),
+ new Color(255, 199, 87, 100),
+ new Color(119, 105, 198, 100),
+ new Color(135, 199, 112, 100),
+ new Color(240, 37, 240, 100),
+ new Color(178, 132, 190, 100),
+ new Color(63, 135, 163, 100),
+ new Color(146, 74, 10, 100),
+ new Color(255, 255, 255, 100),
+ new Color(217, 252, 140, 100),
+ new Color(255, 82, 82, 100)
+ };
+
+ Iterator<Color> colorIterator = Arrays.stream(colors).iterator();
+
+ matches.forEach((itemName, slotSet) -> {
+ if (slotSet.size() < 2) return;
+ ArrayList<Slot> slots = new ArrayList<>();
+ slotSet.forEach(slotNum -> slots.add(event.slots.get(slotNum)));
+ Color color = colorIterator.next();
+ slots.forEach(slot -> {
+ Utils.drawOnSlot(event.chestSize, slot.xDisplayPosition, slot.yDisplayPosition, color.getRGB());
+ });
+ });
+ }
+ }
+
+ @SubscribeEvent
+ public void onGuiOpen(GuiOpenEvent event) {
+ experimentTableSlots = new ItemStack[54];
+ }
+
+}
diff --git a/src/main/java/me/Danker/features/puzzlesolvers/ThreeManSolver.java b/src/main/java/me/Danker/features/puzzlesolvers/ThreeManSolver.java
new file mode 100644
index 0000000..8f7de95
--- /dev/null
+++ b/src/main/java/me/Danker/features/puzzlesolvers/ThreeManSolver.java
@@ -0,0 +1,75 @@
+package me.Danker.features.puzzlesolvers;
+
+import me.Danker.DankersSkyblockMod;
+import me.Danker.commands.ToggleCommand;
+import me.Danker.utils.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.entity.Entity;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.*;
+import net.minecraftforge.client.event.ClientChatReceivedEvent;
+import net.minecraftforge.client.event.RenderWorldLastEvent;
+import net.minecraftforge.event.world.WorldEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+
+import java.util.List;
+
+public class ThreeManSolver {
+
+ static String[] riddleSolutions = {"The reward is not in my chest!", "At least one of them is lying, and the reward is not in",
+ "My chest doesn't have the reward. We are all telling the truth", "My chest has the reward and I'm telling the truth",
+ "The reward isn't in any of our chests", "Both of them are telling the truth."};
+ static BlockPos riddleChest = null;
+
+ @SubscribeEvent
+ public void onWorldChange(WorldEvent.Load event) {
+ riddleChest = null;
+ }
+
+ @SubscribeEvent
+ public void onChat(ClientChatReceivedEvent event) {
+ String message = StringUtils.stripControlCodes(event.message.getUnformattedText());
+
+ if (!Utils.inDungeons) return;
+
+ if (ToggleCommand.threeManToggled && message.contains("[NPC]")) {
+ for (String solution : riddleSolutions) {
+ if (message.contains(solution)) {
+ Minecraft mc = Minecraft.getMinecraft();
+ String npcName = message.substring(message.indexOf("]") + 2, message.indexOf(":"));
+ mc.thePlayer.addChatMessage(new ChatComponentText(DankersSkyblockMod.ANSWER_COLOUR + EnumChatFormatting.BOLD + StringUtils.stripControlCodes(npcName) + DankersSkyblockMod.MAIN_COLOUR + " has the blessing."));
+ if (riddleChest == null) {
+ List<Entity> entities = mc.theWorld.getLoadedEntityList();
+ for (Entity entity : entities) {
+ if (entity == null || !entity.hasCustomName()) continue;
+ if (entity.getCustomNameTag().contains(npcName)) {
+ BlockPos npcLocation = new BlockPos(entity.posX, 69, entity.posZ);
+ if (mc.theWorld.getBlockState(npcLocation.north()).getBlock() == Blocks.chest) {
+ riddleChest = npcLocation.north();
+ } else if (mc.theWorld.getBlockState(npcLocation.east()).getBlock() == Blocks.chest) {
+ riddleChest = npcLocation.east();
+ } else if (mc.theWorld.getBlockState(npcLocation.south()).getBlock() == Blocks.chest) {
+ riddleChest = npcLocation.south();
+ } else if (mc.theWorld.getBlockState(npcLocation.west()).getBlock() == Blocks.chest) {
+ riddleChest = npcLocation.west();
+ } else {
+ System.out.print("Could not find correct riddle chest.");
+ }
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void onWorldRender(RenderWorldLastEvent event) {
+ if (ToggleCommand.threeManToggled && riddleChest != null) {
+ Utils.drawFilled3DBox(new AxisAlignedBB(riddleChest.getX() - 0.05, riddleChest.getY(), riddleChest.getZ() - 0.05, riddleChest.getX() + 1.05, riddleChest.getY() + 1, riddleChest.getZ() + 1.05), 0x197F19, true, true, event.partialTicks);
+ }
+ }
+
+}
diff --git a/src/main/java/me/Danker/features/puzzlesolvers/TicTacToeSolver.java b/src/main/java/me/Danker/features/puzzlesolvers/TicTacToeSolver.java
new file mode 100644
index 0000000..1b4a2e1
--- /dev/null
+++ b/src/main/java/me/Danker/features/puzzlesolvers/TicTacToeSolver.java
@@ -0,0 +1,135 @@
+package me.Danker.features.puzzlesolvers;
+
+import me.Danker.DankersSkyblockMod;
+import me.Danker.commands.ToggleCommand;
+import me.Danker.utils.TicTacToeUtils;
+import me.Danker.utils.Utils;
+import net.minecraft.block.Block;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.EntityPlayerSP;
+import net.minecraft.entity.item.EntityItemFrame;
+import net.minecraft.init.Blocks;
+import net.minecraft.item.ItemMap;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.EnumFacing;
+import net.minecraft.world.World;
+import net.minecraft.world.storage.MapData;
+import net.minecraftforge.client.event.RenderWorldLastEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class TicTacToeSolver {
+
+ static AxisAlignedBB correctTicTacToeButton = null;
+
+ @SubscribeEvent
+ public void onTick(TickEvent.ClientTickEvent event) {
+ if (event.phase != TickEvent.Phase.START) return;
+
+ Minecraft mc = Minecraft.getMinecraft();
+ World world = mc.theWorld;
+ EntityPlayerSP player = mc.thePlayer;
+ if (DankersSkyblockMod.tickAmount % 20 == 0) {
+ if (ToggleCommand.ticTacToeToggled && Utils.inDungeons && world != null && player != null) {
+ correctTicTacToeButton = null;
+ AxisAlignedBB aabb = new AxisAlignedBB(player.posX - 6, player.posY - 6, player.posZ - 6, player.posX + 6, player.posY + 6, player.posZ + 6);
+ List<EntityItemFrame> itemFrames = world.getEntitiesWithinAABB(EntityItemFrame.class, aabb);
+ List<EntityItemFrame> itemFramesWithMaps = new ArrayList<>();
+ // Find how many item frames have maps already placed
+ for (EntityItemFrame itemFrame : itemFrames) {
+ ItemStack item = itemFrame.getDisplayedItem();
+ if (item == null || !(item.getItem() instanceof ItemMap)) continue;
+ MapData mapData = ((ItemMap) item.getItem()).getMapData(item, world);
+ if (mapData == null) continue;
+
+ itemFramesWithMaps.add(itemFrame);
+ }
+
+ // Only run when it's your turn
+ if (itemFramesWithMaps.size() != 9 && itemFramesWithMaps.size() % 2 == 1) {
+ char[][] board = new char[3][3];
+ BlockPos leftmostRow = null;
+ int sign = 1;
+ char facing = 'X';
+ for (EntityItemFrame itemFrame : itemFramesWithMaps) {
+ ItemStack map = itemFrame.getDisplayedItem();
+ MapData mapData = ((ItemMap) map.getItem()).getMapData(map, world);
+
+ // Find position on board
+ // I mixed up row and column here and I'm too lazy to fix it
+ int row = 0;
+ int column;
+ sign = 1;
+
+ if (itemFrame.facingDirection == EnumFacing.SOUTH || itemFrame.facingDirection == EnumFacing.WEST) {
+ sign = -1;
+ }
+
+ BlockPos itemFramePos = new BlockPos(itemFrame.posX, Math.floor(itemFrame.posY), itemFrame.posZ);
+ for (int i = 2; i >= 0; i--) {
+ int realI = i * sign;
+ BlockPos blockPos = itemFramePos;
+ if (itemFrame.posX % 0.5 == 0) {
+ blockPos = itemFramePos.add(realI, 0, 0);
+ } else if (itemFrame.posZ % 0.5 == 0) {
+ blockPos = itemFramePos.add(0, 0, realI);
+ facing = 'Z';
+ }
+ Block block = world.getBlockState(blockPos).getBlock();
+ if (block == Blocks.air || block == Blocks.stone_button) {
+ leftmostRow = blockPos;
+ row = i;
+ break;
+ }
+ }
+
+ if (itemFrame.posY == 72.5) {
+ column = 0;
+ } else if (itemFrame.posY == 71.5) {
+ column = 1;
+ } else if (itemFrame.posY == 70.5) {
+ column = 2;
+ } else {
+ continue;
+ }
+
+ // Get colour
+ // Middle pixel = 64*128 + 64 = 8256
+ int colourInt = mapData.colors[8256] & 255;
+ if (colourInt == 114) {
+ board[column][row] = 'X';
+ } else if (colourInt == 33) {
+ board[column][row] = 'O';
+ }
+ }
+ System.out.println("Board: " + Arrays.deepToString(board));
+
+ // Draw best move
+ int bestMove = TicTacToeUtils.getBestMove(board) - 1;
+ System.out.println("Best move slot: " + bestMove);
+ if (leftmostRow != null) {
+ double drawX = facing == 'X' ? leftmostRow.getX() - sign * (bestMove % 3) : leftmostRow.getX();
+ double drawY = 72 - Math.floor(bestMove / 3);
+ double drawZ = facing == 'Z' ? leftmostRow.getZ() - sign * (bestMove % 3) : leftmostRow.getZ();
+
+ correctTicTacToeButton = new AxisAlignedBB(drawX, drawY, drawZ, drawX + 1, drawY + 1, drawZ + 1);
+ }
+ }
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void onWorldRender(RenderWorldLastEvent event) {
+ if (ToggleCommand.ticTacToeToggled && correctTicTacToeButton != null) {
+ Utils.draw3DBox(correctTicTacToeButton, 0x40FF40, event.partialTicks);
+ }
+ }
+
+}
diff --git a/src/main/java/me/Danker/features/puzzlesolvers/TriviaSolver.java b/src/main/java/me/Danker/features/puzzlesolvers/TriviaSolver.java
new file mode 100644
index 0000000..b769634
--- /dev/null
+++ b/src/main/java/me/Danker/features/puzzlesolvers/TriviaSolver.java
@@ -0,0 +1,102 @@
+package me.Danker.features.puzzlesolvers;
+
+import me.Danker.commands.ToggleCommand;
+import me.Danker.utils.Utils;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.StringUtils;
+import net.minecraftforge.client.event.ClientChatReceivedEvent;
+import net.minecraftforge.fml.common.eventhandler.EventPriority;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class TriviaSolver {
+
+ static Map<String, String[]> triviaSolutions = new HashMap<>();
+ static String[] triviaAnswers = null;
+ public static String TRIVIA_WRONG_ANSWER_COLOUR;
+
+ public static void init() {
+ triviaSolutions.put("What is the status of The Watcher?", new String[]{"Stalker"});
+ triviaSolutions.put("What is the status of Bonzo?", new String[]{"New Necromancer"});
+ triviaSolutions.put("What is the status of Scarf?", new String[]{"Apprentice Necromancer"});
+ triviaSolutions.put("What is the status of The Professor?", new String[]{"Professor"});
+ triviaSolutions.put("What is the status of Thorn?", new String[]{"Shaman Necromancer"});
+ triviaSolutions.put("What is the status of Livid?", new String[]{"Master Necromancer"});
+ triviaSolutions.put("What is the status of Sadan?", new String[]{"Necromancer Lord"});
+ triviaSolutions.put("What is the status of Maxor?", new String[]{"Young Wither"});
+ triviaSolutions.put("What is the status of Goldor?", new String[]{"Wither Soldier"});
+ triviaSolutions.put("What is the status of Storm?", new String[]{"Elementalist"});
+ triviaSolutions.put("What is the status of Necron?", new String[]{"Wither Lord"});
+ triviaSolutions.put("How many total Fairy Souls are there?", new String[]{"220 Fairy Souls"});
+ triviaSolutions.put("How many Fairy Souls are there in Spider's Den?", new String[]{"17 Fairy Souls"});
+ triviaSolutions.put("How many Fairy Souls are there in The End?", new String[]{"12 Fairy Souls"});
+ triviaSolutions.put("How many Fairy Souls are there in The Barn?", new String[]{"7 Fairy Souls"});
+ triviaSolutions.put("How many Fairy Souls are there in Mushroom Desert?", new String[]{"8 Fairy Souls"});
+ triviaSolutions.put("How many Fairy Souls are there in Blazing Fortress?", new String[]{"19 Fairy Souls"});
+ triviaSolutions.put("How many Fairy Souls are there in The Park?", new String[]{"11 Fairy Souls"});
+ triviaSolutions.put("How many Fairy Souls are there in Jerry's Workshop?", new String[]{"5 Fairy Souls"});
+ triviaSolutions.put("How many Fairy Souls are there in Hub?", new String[]{"79 Fairy Souls"});
+ triviaSolutions.put("How many Fairy Souls are there in The Hub?", new String[]{"79 Fairy Souls"});
+ triviaSolutions.put("How many Fairy Souls are there in Deep Caverns?", new String[]{"21 Fairy Souls"});
+ triviaSolutions.put("How many Fairy Souls are there in Gold Mine?", new String[]{"12 Fairy Souls"});
+ triviaSolutions.put("How many Fairy Souls are there in Dungeon Hub?", new String[]{"7 Fairy Souls"});
+ triviaSolutions.put("Which brother is on the Spider's Den?", new String[]{"Rick"});
+ triviaSolutions.put("What is the name of Rick's brother?", new String[]{"Pat"});
+ triviaSolutions.put("What is the name of the Painter in the Hub?", new String[]{"Marco"});
+ triviaSolutions.put("What is the name of the person that upgrades pets?", new String[]{"Kat"});
+ triviaSolutions.put("What is the name of the lady of the Nether?", new String[]{"Elle"});
+ triviaSolutions.put("Which villager in the Village gives you a Rogue Sword?", new String[]{"Jamie"});
+ triviaSolutions.put("How many unique minions are there?", new String[]{"53 Minions"});
+ triviaSolutions.put("Which of these enemies does not spawn in the Spider's Den?", new String[]{"Zombie Spider", "Cave Spider", "Wither Skeleton",
+ "Dashing Spooder", "Broodfather", "Night Spider"});
+ triviaSolutions.put("Which of these monsters only spawns at night?", new String[]{"Zombie Villager", "Ghast"});
+ triviaSolutions.put("Which of these is not a dragon in The End?", new String[]{"Zoomer Dragon", "Weak Dragon", "Stonk Dragon", "Holy Dragon", "Boomer Dragon",
+ "Booger Dragon", "Older Dragon", "Elder Dragon", "Stable Dragon", "Professor Dragon"});
+ }
+
+ @SubscribeEvent(priority = EventPriority.HIGHEST)
+ public void onChat(ClientChatReceivedEvent event) {
+ String message = StringUtils.stripControlCodes(event.message.getUnformattedText());
+
+ if (!Utils.inDungeons) return;
+ if (event.type == 2) return;
+
+ if (ToggleCommand.oruoToggled) {
+ if (message.contains("What SkyBlock year is it?")) {
+ double currentTime = System.currentTimeMillis() /1000L;
+
+ double diff = Math.floor(currentTime - 1560276000);
+
+ int year = (int) (diff / 446400 + 1);
+ triviaAnswers = new String[]{"Year " + year};
+ } else {
+ for (String question : triviaSolutions.keySet()) {
+ if (message.contains(question)) {
+ triviaAnswers = triviaSolutions.get(question);
+ break;
+ }
+ }
+ }
+
+ // Set wrong answers to red and remove click events
+ if (triviaAnswers != null && (message.contains("ⓐ") || message.contains("ⓑ") || message.contains("ⓒ"))) {
+ boolean isSolution = false;
+ for (String solution : triviaAnswers) {
+ if (message.contains(solution)) {
+ isSolution = true;
+ break;
+ }
+ }
+ if (!isSolution) {
+ char letter = message.charAt(5);
+ String option = message.substring(6);
+ event.message = new ChatComponentText(" " + EnumChatFormatting.GOLD + letter + TRIVIA_WRONG_ANSWER_COLOUR + option);
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/me/Danker/features/puzzlesolvers/UltrasequencerSolver.java b/src/main/java/me/Danker/features/puzzlesolvers/UltrasequencerSolver.java
new file mode 100644
index 0000000..87309fe
--- /dev/null
+++ b/src/main/java/me/Danker/features/puzzlesolvers/UltrasequencerSolver.java
@@ -0,0 +1,112 @@
+package me.Danker.features.puzzlesolvers;
+
+import me.Danker.commands.ToggleCommand;
+import me.Danker.events.ChestSlotClickedEvent;
+import me.Danker.events.GuiChestBackgroundDrawnEvent;
+import me.Danker.utils.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.EntityPlayerSP;
+import net.minecraft.client.gui.inventory.GuiChest;
+import net.minecraft.inventory.ContainerChest;
+import net.minecraft.inventory.IInventory;
+import net.minecraft.inventory.Slot;
+import net.minecraft.util.StringUtils;
+import net.minecraftforge.client.event.GuiOpenEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
+import org.lwjgl.input.Keyboard;
+
+import java.util.List;
+
+public class UltrasequencerSolver {
+
+ static Slot[] clickInOrderSlots = new Slot[36];
+ static int lastUltraSequencerClicked = 0;
+ public static int ULTRASEQUENCER_NEXT;
+ public static int ULTRASEQUENCER_NEXT_TO_NEXT;
+
+ @SubscribeEvent
+ public void onTick(TickEvent.ClientTickEvent event) {
+ if (event.phase != TickEvent.Phase.START) return;
+
+ Minecraft mc = Minecraft.getMinecraft();
+ EntityPlayerSP player = mc.thePlayer;
+ if (mc.currentScreen instanceof GuiChest) {
+ if (player == null) return;
+ ContainerChest chest = (ContainerChest) player.openContainer;
+ List<Slot> invSlots = ((GuiChest) mc.currentScreen).inventorySlots.inventorySlots;
+ String chestName = chest.getLowerChestInventory().getDisplayName().getUnformattedText().trim();
+
+ if (ToggleCommand.ultrasequencerToggled && chestName.startsWith("Ultrasequencer (")) {
+ if (invSlots.get(49).getStack() != null && invSlots.get(49).getStack().getDisplayName().equals("§aRemember the pattern!")) {
+ for (int i = 9; i <= 44; i++) {
+ if (invSlots.get(i) == null || invSlots.get(i).getStack() == null) continue;
+ String itemName = StringUtils.stripControlCodes(invSlots.get(i).getStack().getDisplayName());
+ if (itemName.matches("\\d+")) {
+ int number = Integer.parseInt(itemName);
+ clickInOrderSlots[number - 1] = invSlots.get(i);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void onSlotClick(ChestSlotClickedEvent event) {
+ if (ToggleCommand.ultrasequencerToggled && event.inventoryName.startsWith("Ultrasequencer (")) {
+ IInventory inventory = event.inventory;
+ if (event.item == null) {
+ if (event.isCancelable() && !Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) && !Keyboard.isKeyDown(Keyboard.KEY_RCONTROL))
+ event.setCanceled(true);
+ return;
+ }
+ if (inventory.getStackInSlot(49).getDisplayName().equals("§aRemember the pattern!")) {
+ if (event.isCancelable()) event.setCanceled(true);
+ return;
+ } else if (inventory.getStackInSlot(49).getDisplayName().startsWith("§7Timer: §a")) {
+ if (clickInOrderSlots[lastUltraSequencerClicked] != null && event.slot.getSlotIndex() != clickInOrderSlots[lastUltraSequencerClicked].getSlotIndex()) {
+ if (event.isCancelable() && !Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) && !Keyboard.isKeyDown(Keyboard.KEY_RCONTROL))
+ event.setCanceled(true);
+ return;
+ }
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void onGuiRender(GuiChestBackgroundDrawnEvent event) {
+ if (ToggleCommand.ultrasequencerToggled && event.displayName.startsWith("Ultrasequencer (")) {
+ List<Slot> invSlots = event.slots;
+ if (invSlots.size() > 48 && invSlots.get(49).getStack() != null) {
+ if (invSlots.get(49).getStack().getDisplayName().startsWith("§7Timer: §a")) {
+ lastUltraSequencerClicked = 0;
+ for (Slot slot : clickInOrderSlots) {
+ if (slot != null && slot.getStack() != null && StringUtils.stripControlCodes(slot.getStack().getDisplayName()).matches("\\d+")) {
+ int number = Integer.parseInt(StringUtils.stripControlCodes(slot.getStack().getDisplayName()));
+ if (number > lastUltraSequencerClicked) {
+ lastUltraSequencerClicked = number;
+ }
+ }
+ }
+ if (clickInOrderSlots[lastUltraSequencerClicked] != null) {
+ Slot nextSlot = clickInOrderSlots[lastUltraSequencerClicked];
+ Utils.drawOnSlot(event.chestSize, nextSlot.xDisplayPosition, nextSlot.yDisplayPosition, ULTRASEQUENCER_NEXT + 0xE5000000);
+ }
+ if (lastUltraSequencerClicked + 1 < clickInOrderSlots.length) {
+ if (clickInOrderSlots[lastUltraSequencerClicked + 1] != null) {
+ Slot nextSlot = clickInOrderSlots[lastUltraSequencerClicked + 1];
+ Utils.drawOnSlot(event.chestSize, nextSlot.xDisplayPosition, nextSlot.yDisplayPosition, ULTRASEQUENCER_NEXT_TO_NEXT + 0xD7000000);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void onGuiOpen(GuiOpenEvent event) {
+ clickInOrderSlots = new Slot[36];
+ }
+
+}
diff --git a/src/main/java/me/Danker/features/puzzlesolvers/WaterSolver.java b/src/main/java/me/Danker/features/puzzlesolvers/WaterSolver.java
new file mode 100644
index 0000000..2be92f9
--- /dev/null
+++ b/src/main/java/me/Danker/features/puzzlesolvers/WaterSolver.java
@@ -0,0 +1,162 @@
+package me.Danker.features.puzzlesolvers;
+
+import me.Danker.DankersSkyblockMod;
+import me.Danker.commands.MoveCommand;
+import me.Danker.commands.ScaleCommand;
+import me.Danker.commands.ToggleCommand;
+import me.Danker.events.RenderOverlay;
+import me.Danker.handlers.TextRenderer;
+import me.Danker.utils.Utils;
+import net.minecraft.block.Block;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.EntityPlayerSP;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.world.World;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
+
+public class WaterSolver {
+
+ static boolean prevInWaterRoom = false;
+ static boolean inWaterRoom = false;
+ static String waterAnswers = null;
+
+ @SubscribeEvent
+ public void onTick(TickEvent.ClientTickEvent event) {
+ if (event.phase != TickEvent.Phase.START) return;
+
+ Minecraft mc = Minecraft.getMinecraft();
+ EntityPlayerSP player = mc.thePlayer;
+ World world = mc.theWorld;
+ if (DankersSkyblockMod.tickAmount % 20 == 0) {
+ if (ToggleCommand.waterToggled && Utils.inDungeons && world != null && player != null) {
+ // multi thread block checking
+ new Thread(() -> {
+ prevInWaterRoom = inWaterRoom;
+ inWaterRoom = false;
+ boolean foundPiston = false;
+ boolean done = false;
+ for (int x = (int) (player.posX - 13); x <= player.posX + 13; x++) {
+ for (int z = (int) (player.posZ - 13); z <= player.posZ + 13; z++) {
+ BlockPos blockPos = new BlockPos(x, 54, z);
+ if (world.getBlockState(blockPos).getBlock() == Blocks.sticky_piston) {
+ foundPiston = true;
+ break;
+ }
+ }
+ if (foundPiston) break;
+ }
+
+ if (foundPiston) {
+ for (int x = (int) (player.posX - 25); x <= player.posX + 25; x++) {
+ for (int z = (int) (player.posZ - 25); z <= player.posZ + 25; z++) {
+ BlockPos blockPos = new BlockPos(x, 82, z);
+ if (world.getBlockState(blockPos).getBlock() == Blocks.piston_head) {
+ inWaterRoom = true;
+ if (!prevInWaterRoom) {
+ boolean foundGold = false;
+ boolean foundClay = false;
+ boolean foundEmerald = false;
+ boolean foundQuartz = false;
+ boolean foundDiamond = false;
+
+ // Detect first blocks near water stream
+ BlockPos scan1 = new BlockPos(x + 1, 78, z + 1);
+ BlockPos scan2 = new BlockPos(x - 1, 77, z - 1);
+ Iterable<BlockPos> blocks = BlockPos.getAllInBox(scan1, scan2);
+ for (BlockPos puzzleBlockPos : blocks) {
+ Block block = world.getBlockState(puzzleBlockPos).getBlock();
+ if (block == Blocks.gold_block) {
+ foundGold = true;
+ } else if (block == Blocks.hardened_clay) {
+ foundClay = true;
+ } else if (block == Blocks.emerald_block) {
+ foundEmerald = true;
+ } else if (block == Blocks.quartz_block) {
+ foundQuartz = true;
+ } else if (block == Blocks.diamond_block) {
+ foundDiamond = true;
+ }
+ }
+
+ int variant = 0;
+ if (foundGold && foundClay) {
+ variant = 1;
+ } else if (foundEmerald && foundQuartz) {
+ variant = 2;
+ } else if (foundQuartz && foundDiamond) {
+ variant = 3;
+ } else if (foundGold && foundQuartz) {
+ variant = 4;
+ }
+
+ // Return solution
+ String purple;
+ String orange;
+ String blue;
+ String green;
+ String red;
+ switch (variant) {
+ case 1:
+ purple = EnumChatFormatting.WHITE + "Quartz, " + EnumChatFormatting.YELLOW + "Gold, " + EnumChatFormatting.AQUA + "Diamond, " + EnumChatFormatting.RED + "Clay";
+ orange = EnumChatFormatting.YELLOW + "Gold, " + EnumChatFormatting.DARK_GRAY + "Coal, " + EnumChatFormatting.GREEN + "Emerald";
+ blue = EnumChatFormatting.WHITE + "Quartz, " + EnumChatFormatting.YELLOW + "Gold, " + EnumChatFormatting.GREEN + "Emerald, " + EnumChatFormatting.RED + "Clay";
+ green = EnumChatFormatting.GREEN + "Emerald";
+ red = EnumChatFormatting.GRAY + "None";
+ break;
+ case 2:
+ purple = EnumChatFormatting.DARK_GRAY + "Coal";
+ orange = EnumChatFormatting.WHITE + "Quartz, " + EnumChatFormatting.YELLOW + "Gold, " + EnumChatFormatting.GREEN + "Emerald, " + EnumChatFormatting.RED + "Clay";
+ blue = EnumChatFormatting.WHITE + "Quartz, " + EnumChatFormatting.AQUA + "Diamond, " + EnumChatFormatting.GREEN + "Emerald";
+ green = EnumChatFormatting.WHITE + "Quartz, " + EnumChatFormatting.GREEN + "Emerald";
+ red = EnumChatFormatting.WHITE + "Quartz, " + EnumChatFormatting.DARK_GRAY + "Coal, " + EnumChatFormatting.GREEN + "Emerald";
+ break;
+ case 3:
+ purple = EnumChatFormatting.WHITE + "Quartz, " + EnumChatFormatting.YELLOW + "Gold, " + EnumChatFormatting.AQUA + "Diamond";
+ orange = EnumChatFormatting.GREEN + "Emerald";
+ blue = EnumChatFormatting.WHITE + "Quartz, " + EnumChatFormatting.AQUA + "Diamond";
+ green = EnumChatFormatting.GRAY + "None";
+ red = EnumChatFormatting.YELLOW + "Gold, " + EnumChatFormatting.GREEN + "Emerald";
+ break;
+ case 4:
+ purple = EnumChatFormatting.WHITE + "Quartz, " + EnumChatFormatting.YELLOW + "Gold, " + EnumChatFormatting.GREEN + "Emerald, " + EnumChatFormatting.RED + "Clay";
+ orange = EnumChatFormatting.YELLOW + "Gold, " + EnumChatFormatting.DARK_GRAY + "Coal";
+ blue = EnumChatFormatting.WHITE + "Quartz, " + EnumChatFormatting.YELLOW + "Gold, " + EnumChatFormatting.DARK_GRAY + "Coal, " + EnumChatFormatting.GREEN + "Emerald, " + EnumChatFormatting.RED + "Clay";
+ green = EnumChatFormatting.YELLOW + "Gold, " + EnumChatFormatting.GREEN + "Emerald";
+ red = EnumChatFormatting.YELLOW + "Gold, " + EnumChatFormatting.AQUA + "Diamond, " + EnumChatFormatting.GREEN + "Emerald, " + EnumChatFormatting.RED + "Clay";
+ break;
+ default:
+ purple = orange = blue = green = red = DankersSkyblockMod.ERROR_COLOUR + "Error detecting water puzzle variant.";
+ break;
+ }
+ waterAnswers = DankersSkyblockMod.MAIN_COLOUR + "The following levers must be down:\n" +
+ EnumChatFormatting.DARK_PURPLE + "Purple: " + purple + "\n" +
+ EnumChatFormatting.GOLD + "Orange: " + orange + "\n" +
+ EnumChatFormatting.BLUE + "Blue: " + blue + "\n" +
+ EnumChatFormatting.GREEN + "Green: " + green + "\n" +
+ EnumChatFormatting.RED + "Red: " + red;
+ done = true;
+ break;
+ }
+ }
+ }
+ if (done) break;
+ }
+ } else {
+ waterAnswers = null;
+ }
+ }).start();
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void renderPlayerInfo(RenderOverlay event) {
+ if (ToggleCommand.waterToggled && Utils.inDungeons && waterAnswers != null) {
+ new TextRenderer(Minecraft.getMinecraft(), waterAnswers, MoveCommand.waterAnswerXY[0], MoveCommand.waterAnswerXY[1], ScaleCommand.waterAnswerScale);
+ }
+ }
+
+}