From 42449d4110853d43b40c50f96c2814b865d24f8d Mon Sep 17 00:00:00 2001
From: bowser0000 <bowser0000@gmail.com>
Date: Thu, 18 Mar 2021 18:24:48 -0400
Subject: Add custom dungeon boss music

---
 src/main/java/me/Danker/DankersSkyblockMod.java    |  59 ++++++-----
 .../me/Danker/commands/CustomMusicCommand.java     |  70 ++++++++++++
 src/main/java/me/Danker/commands/DHelpCommand.java |   5 +-
 .../java/me/Danker/commands/DankerGuiCommand.java  |   3 +-
 .../java/me/Danker/commands/ToggleCommand.java     |  25 ++++-
 src/main/java/me/Danker/features/CustomMusic.java  | 117 +++++++++++++++++++++
 src/main/java/me/Danker/gui/DankerGui.java         |  17 ++-
 .../java/me/Danker/handlers/ConfigHandler.java     |   2 +
 8 files changed, 265 insertions(+), 33 deletions(-)
 create mode 100644 src/main/java/me/Danker/commands/CustomMusicCommand.java
 create mode 100644 src/main/java/me/Danker/features/CustomMusic.java

(limited to 'src')

diff --git a/src/main/java/me/Danker/DankersSkyblockMod.java b/src/main/java/me/Danker/DankersSkyblockMod.java
index ab042d6..4a40a61 100644
--- a/src/main/java/me/Danker/DankersSkyblockMod.java
+++ b/src/main/java/me/Danker/DankersSkyblockMod.java
@@ -53,6 +53,9 @@ import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientConnectedToSe
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.input.Mouse;
 
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.UnsupportedAudioFileException;
+import java.io.IOException;
 import java.util.List;
 import java.util.Map;
 
@@ -70,6 +73,7 @@ public class DankersSkyblockMod {
     static boolean OAMWarning = false;
     public static String guiToOpen = null;
     public static boolean firstLaunch = false;
+    public static String configDirectory;
     
     public static String MAIN_COLOUR;
     public static String SECONDARY_COLOUR;
@@ -97,6 +101,7 @@ public class DankersSkyblockMod {
         MinecraftForge.EVENT_BUS.register(new ChronomatronSolver());
         MinecraftForge.EVENT_BUS.register(new ClickInOrderSolver());
         MinecraftForge.EVENT_BUS.register(new CreeperSolver());
+        MinecraftForge.EVENT_BUS.register(new CustomMusic());
         MinecraftForge.EVENT_BUS.register(new DungeonTimer());
         MinecraftForge.EVENT_BUS.register(new ExpertiseLore());
         MinecraftForge.EVENT_BUS.register(new FasterMaddoxCalling());
@@ -145,31 +150,35 @@ public class DankersSkyblockMod {
     }
 
     @EventHandler
-    public void preInit(final FMLPreInitializationEvent event) {
-    	ClientCommandHandler.instance.registerCommand(new ToggleCommand());
-    	ClientCommandHandler.instance.registerCommand(new SetkeyCommand());
-    	ClientCommandHandler.instance.registerCommand(new GetkeyCommand());
-    	ClientCommandHandler.instance.registerCommand(new LootCommand());
-    	ClientCommandHandler.instance.registerCommand(new ReloadConfigCommand());
-    	ClientCommandHandler.instance.registerCommand(new DisplayCommand());
-    	ClientCommandHandler.instance.registerCommand(new MoveCommand());
-    	ClientCommandHandler.instance.registerCommand(new SlayerCommand());
-    	ClientCommandHandler.instance.registerCommand(new SkillsCommand());
-    	ClientCommandHandler.instance.registerCommand(new GuildOfCommand());
-    	ClientCommandHandler.instance.registerCommand(new DHelpCommand());
-    	ClientCommandHandler.instance.registerCommand(new PetsCommand());
-    	ClientCommandHandler.instance.registerCommand(new BankCommand());
-    	ClientCommandHandler.instance.registerCommand(new ArmourCommand());
-    	ClientCommandHandler.instance.registerCommand(new ImportFishingCommand());
-    	ClientCommandHandler.instance.registerCommand(new ResetLootCommand());
-    	ClientCommandHandler.instance.registerCommand(new ScaleCommand());
-    	ClientCommandHandler.instance.registerCommand(new SkyblockPlayersCommand());
-    	ClientCommandHandler.instance.registerCommand(new BlockSlayerCommand());
-    	ClientCommandHandler.instance.registerCommand(new DungeonsCommand());
-    	ClientCommandHandler.instance.registerCommand(new LobbySkillsCommand());
-    	ClientCommandHandler.instance.registerCommand(new DankerGuiCommand());
-		ClientCommandHandler.instance.registerCommand(new SkillTrackerCommand());
-		ClientCommandHandler.instance.registerCommand(new FairySoulsCommand());
+    public void preInit(final FMLPreInitializationEvent event) throws UnsupportedAudioFileException, IOException, LineUnavailableException {
+        ClientCommandHandler.instance.registerCommand(new ArmourCommand());
+        ClientCommandHandler.instance.registerCommand(new BankCommand());
+        ClientCommandHandler.instance.registerCommand(new BlockSlayerCommand());
+        ClientCommandHandler.instance.registerCommand(new CustomMusicCommand());
+        ClientCommandHandler.instance.registerCommand(new DHelpCommand());
+        ClientCommandHandler.instance.registerCommand(new DankerGuiCommand());
+        ClientCommandHandler.instance.registerCommand(new DisplayCommand());
+        ClientCommandHandler.instance.registerCommand(new DungeonsCommand());
+        ClientCommandHandler.instance.registerCommand(new FairySoulsCommand());
+        ClientCommandHandler.instance.registerCommand(new GetkeyCommand());
+        ClientCommandHandler.instance.registerCommand(new GuildOfCommand());
+        ClientCommandHandler.instance.registerCommand(new ImportFishingCommand());
+        ClientCommandHandler.instance.registerCommand(new LobbySkillsCommand());
+        ClientCommandHandler.instance.registerCommand(new LootCommand());
+        ClientCommandHandler.instance.registerCommand(new MoveCommand());
+        ClientCommandHandler.instance.registerCommand(new PetsCommand());
+        ClientCommandHandler.instance.registerCommand(new ReloadConfigCommand());
+        ClientCommandHandler.instance.registerCommand(new ResetLootCommand());
+        ClientCommandHandler.instance.registerCommand(new ScaleCommand());
+        ClientCommandHandler.instance.registerCommand(new SetkeyCommand());
+        ClientCommandHandler.instance.registerCommand(new SkillTrackerCommand());
+        ClientCommandHandler.instance.registerCommand(new SkillsCommand());
+        ClientCommandHandler.instance.registerCommand(new SkyblockPlayersCommand());
+        ClientCommandHandler.instance.registerCommand(new SlayerCommand());
+        ClientCommandHandler.instance.registerCommand(new ToggleCommand());
+
+        configDirectory = event.getModConfigurationDirectory().toString();
+		CustomMusic.init(configDirectory);
     }
 
     @EventHandler
diff --git a/src/main/java/me/Danker/commands/CustomMusicCommand.java b/src/main/java/me/Danker/commands/CustomMusicCommand.java
new file mode 100644
index 0000000..5364930
--- /dev/null
+++ b/src/main/java/me/Danker/commands/CustomMusicCommand.java
@@ -0,0 +1,70 @@
+package me.Danker.commands;
+
+import me.Danker.DankersSkyblockMod;
+import me.Danker.features.CustomMusic;
+import net.minecraft.command.CommandBase;
+import net.minecraft.command.CommandException;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.ChatComponentText;
+
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.UnsupportedAudioFileException;
+import java.io.IOException;
+import java.util.List;
+
+public class CustomMusicCommand extends CommandBase {
+
+    @Override
+    public String getCommandName() {
+        return "dsmmusic";
+    }
+
+    @Override
+    public String getCommandUsage(ICommandSender arg0) {
+        return "/" + getCommandName() + " <stop/reload>";
+    }
+
+    @Override
+    public int getRequiredPermissionLevel() {
+        return 0;
+    }
+
+    @Override
+    public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {
+        if (args.length == 1) {
+            return getListOfStringsMatchingLastWord(args, "stop", "reload");
+        }
+        return null;
+    }
+
+    @Override
+    public void processCommand(ICommandSender arg0, String[] arg1) throws CommandException {
+        final EntityPlayer player = (EntityPlayer)arg0;
+
+        if (arg1.length == 0) {
+            player.addChatMessage(new ChatComponentText(DankersSkyblockMod.ERROR_COLOUR + "Usage: " + getCommandUsage(arg0)));
+            return;
+        }
+
+        switch (arg1[0].toLowerCase()) {
+            case "stop":
+                if (CustomMusic.dungeonboss != null) CustomMusic.dungeonboss.stop();
+                player.addChatMessage(new ChatComponentText(DankersSkyblockMod.MAIN_COLOUR + "Stopped custom music."));
+                break;
+            case "reload":
+                try {
+                    CustomMusic.init(DankersSkyblockMod.configDirectory);
+                    player.addChatMessage(new ChatComponentText(DankersSkyblockMod.MAIN_COLOUR + "Reloaded custom music."));
+                } catch (IOException | LineUnavailableException | UnsupportedAudioFileException e) {
+                    player.addChatMessage(new ChatComponentText(DankersSkyblockMod.ERROR_COLOUR + "An error occurred while trying to reload music."));
+                    e.printStackTrace();
+                }
+                break;
+            default:
+                player.addChatMessage(new ChatComponentText(DankersSkyblockMod.ERROR_COLOUR + "Usage: " + getCommandUsage(arg0)));
+        }
+    }
+
+}
diff --git a/src/main/java/me/Danker/commands/DHelpCommand.java b/src/main/java/me/Danker/commands/DHelpCommand.java
index c431123..0348574 100644
--- a/src/main/java/me/Danker/commands/DHelpCommand.java
+++ b/src/main/java/me/Danker/commands/DHelpCommand.java
@@ -34,7 +34,7 @@ public class DHelpCommand extends CommandBase {
 													EnumChatFormatting.GOLD + " Commands, " + EnumChatFormatting.GREEN + " Keybinds.\n" +
 													EnumChatFormatting.GOLD + " /dhelp" + EnumChatFormatting.AQUA + " - Returns this message.\n" +
 													EnumChatFormatting.GOLD + " /dsm" + EnumChatFormatting.AQUA + " - Opens the GUI for Danker's Skyblock Mod.\n" +
-													EnumChatFormatting.GOLD + " /toggle <gparty/coords/golden/slayercount/rngesusalerts/splitfishing/chatmaddox/spiritbearalerts/aotd/lividdagger/flowerweapons/sceptremessages/midasstaffmessages/implosionmessages/healmessages/cooldownmessages/manamessages/killcombomessages/petcolors/dungeontimer/golemalerts/expertiselore/skill50display/outlinetext/caketimer/lowhealthnotify/lividsolver/stopsalvagestarred/notifyslayerslain/autoskilltracker/necronnotifications/bonzotimer/threemanpuzzle/oruopuzzle/blazepuzzle/creeperpuzzle/waterpuzzle/tictactoepuzzle/boulderpuzzle/silverfishpuzzle/icewalkpuzzle/watchermessage/startswithterminal/selectallterminal/clickinorderterminal/blockwrongterminalclicks/itemframeonsealanterns/ultrasequencer/chronomatron/superpairs/hidetooltipsinaddons/pickblock/list>" + EnumChatFormatting.AQUA + " - Toggles features. /toggle list returns values of every toggle.\n" +
+													EnumChatFormatting.GOLD + " /toggle <gparty/coords/golden/slayercount/rngesusalerts/splitfishing/chatmaddox/spiritbearalerts/aotd/lividdagger/flowerweapons/sceptremessages/midasstaffmessages/implosionmessages/healmessages/cooldownmessages/manamessages/killcombomessages/petcolors/dungeontimer/golemalerts/expertiselore/skill50display/outlinetext/caketimer/lowhealthnotify/lividsolver/stopsalvagestarred/notifyslayerslain/autoskilltracker/necronnotifications/bonzotimer/threemanpuzzle/oruopuzzle/blazepuzzle/creeperpuzzle/waterpuzzle/tictactoepuzzle/boulderpuzzle/silverfishpuzzle/icewalkpuzzle/watchermessage/startswithterminal/selectallterminal/clickinorderterminal/blockwrongterminalclicks/itemframeonsealanterns/ultrasequencer/chronomatron/superpairs/hidetooltipsinaddons/pickblock/dungeonbossmusic/list>" + EnumChatFormatting.AQUA + " - Toggles features. /toggle list returns values of every toggle.\n" +
 													EnumChatFormatting.GOLD + " /setkey <key>" + EnumChatFormatting.AQUA + " - Sets API key.\n" +
 													EnumChatFormatting.GOLD + " /getkey" + EnumChatFormatting.AQUA + " - Returns key set with /setkey and copies it to your clipboard.\n" +
 													EnumChatFormatting.GOLD + " /loot <zombie/spider/wolf/fishing/catacombs/mythological/> [winter/festival/spooky/f(1-7)/session]" + EnumChatFormatting.AQUA + " - Returns loot received from slayer quests or fishing stats. /loot fishing winter returns winter sea creatures instead.\n" +
@@ -54,7 +54,8 @@ public class DHelpCommand extends CommandBase {
 													EnumChatFormatting.GOLD + " /sbplayers" + EnumChatFormatting.AQUA + " - Uses API to find how many players are on each Skyblock island.\n" +
 													EnumChatFormatting.GOLD + " /onlyslayer <zombie/spider/wolf> <1/2/3/4/5>" + EnumChatFormatting.AQUA + " - Stops you from starting a slayer quest other than the one specified.\n" +
 													EnumChatFormatting.GOLD + " /skilltracker <start/stop/reset>" + EnumChatFormatting.AQUA + " - Text display for skill xp/hour.\n" +
-													EnumChatFormatting.GOLD + " /reparty " + EnumChatFormatting.AQUA + " - Disbands and reparties all members in the party.\n" +
+													EnumChatFormatting.GOLD + " /reparty" + EnumChatFormatting.AQUA + " - Disbands and reparties all members in the party.\n" +
+													EnumChatFormatting.GOLD + " /dsmmusic <stop/reload>" + EnumChatFormatting.AQUA + " - Stops or reloads the custom music.\n" +
 													EnumChatFormatting.GREEN + " Open Maddox Menu" + EnumChatFormatting.AQUA + " - M by default.\n" +
 													EnumChatFormatting.GREEN + " Start/Stop Skill Tracker" + EnumChatFormatting.AQUA + " - Numpad 5 by default.\n"));
 	}
diff --git a/src/main/java/me/Danker/commands/DankerGuiCommand.java b/src/main/java/me/Danker/commands/DankerGuiCommand.java
index bd92b3e..6774d5a 100644
--- a/src/main/java/me/Danker/commands/DankerGuiCommand.java
+++ b/src/main/java/me/Danker/commands/DankerGuiCommand.java
@@ -89,6 +89,7 @@ public class DankerGuiCommand extends CommandBase {
 			debug.append("[superpairs][").append(ToggleCommand.superpairsToggled).append("]\n");
 			debug.append("[hidetooltipsinaddons][").append(ToggleCommand.hideTooltipsInExperimentAddonsToggled).append("]\n");
 			debug.append("[pickblock][").append(ToggleCommand.swapToPickBlockToggled).append("]\n");
+			debug.append("[dungeonbossmusic][").append(ToggleCommand.dungeonBossMusic).append("]\n");
 			debug.append("# Locations\n");
 			debug.append("[coords][").append(MoveCommand.coordsXY[0]).append(", ").append(MoveCommand.coordsXY[1]).append("]\n");
 			debug.append("[display][").append(MoveCommand.displayXY[0]).append(", ").append(MoveCommand.displayXY[1]).append("]\n");
@@ -110,7 +111,7 @@ public class DankerGuiCommand extends CommandBase {
 				debug.append("<None>\n");
 			} else {
 				for (ResourcePackRepository.Entry resource : Minecraft.getMinecraft().getResourcePackRepository().getRepositoryEntries()) {
-					debug.append("< ").append(StringUtils.stripControlCodes(resource.getResourcePackName())).append(" >\n");
+					debug.append("<").append(StringUtils.stripControlCodes(resource.getResourcePackName())).append(">\n");
 				}
 			}
 			debug.append("```");
diff --git a/src/main/java/me/Danker/commands/ToggleCommand.java b/src/main/java/me/Danker/commands/ToggleCommand.java
index 06619ac..2cc4745 100644
--- a/src/main/java/me/Danker/commands/ToggleCommand.java
+++ b/src/main/java/me/Danker/commands/ToggleCommand.java
@@ -1,6 +1,7 @@
 package me.Danker.commands;
 
 import me.Danker.DankersSkyblockMod;
+import me.Danker.features.CustomMusic;
 import me.Danker.handlers.ConfigHandler;
 import net.minecraft.command.CommandBase;
 import net.minecraft.command.CommandException;
@@ -70,7 +71,9 @@ public class ToggleCommand extends CommandBase implements ICommand {
 	public static boolean chronomatronToggled;
 	public static boolean superpairsToggled;
 	public static boolean hideTooltipsInExperimentAddonsToggled;
-	
+	// Custom Music
+	public static boolean dungeonBossMusic;
+
 	@Override
 	public String getCommandName() {
 		return "toggle";
@@ -86,7 +89,8 @@ public class ToggleCommand extends CommandBase implements ICommand {
 										  "notifyslayerslain/necronnotifications/bonzotimer/threemanpuzzle/oruopuzzle/blazepuzzle/" +
 										  "creeperpuzzle/waterpuzzle/tictactoepuzzle/boulderpuzzle/silverfishpuzzle/icewalkpuzzle/watchermessage/" +
 										  "startswithterminal/selectallterminal/clickinorderterminal/blockwrongterminalclicks/" +
-										  "itemframeonsealanterns/ultrasequencer/chronomatron/superpairs/hidetooltipsinaddons/pickblock/list>";
+										  "itemframeonsealanterns/ultrasequencer/chronomatron/superpairs/hidetooltipsinaddons/" +
+										  "pickblock/dungeonbossmusic/list>";
 	}
 
 	@Override
@@ -109,7 +113,7 @@ public class ToggleCommand extends CommandBase implements ICommand {
 														  "silverfishpuzzle", "icewalkpuzzle", "watchermessage", "startswithterminal",
 														  "selectallterminal", "clickinorderterminal", "blockwrongterminalclicks",
 														  "itemframeonsealanterns", "ultrasequencer", "chronomatron", "superpairs",
-														  "hidetooltipsinaddons", "pickblock", "list");
+														  "hidetooltipsinaddons", "pickblock", "dungeonbossmusic", "list");
 		}
 		return null;
 	}
@@ -385,6 +389,18 @@ public class ToggleCommand extends CommandBase implements ICommand {
 				ConfigHandler.writeBooleanConfig("toggles", "PickBlock", swapToPickBlockToggled);
 				player.addChatMessage(new ChatComponentText(DankersSkyblockMod.MAIN_COLOUR + "Auto-swap to pick block has been set to " + DankersSkyblockMod.SECONDARY_COLOUR + swapToPickBlockToggled + DankersSkyblockMod.MAIN_COLOUR + "."));
 				break;
+			case "dungeonbossmusic":
+				dungeonBossMusic = !dungeonBossMusic;
+				if (CustomMusic.dungeonboss != null) {
+					if (dungeonBossMusic) {
+						CustomMusic.start();
+					} else {
+						CustomMusic.dungeonboss.stop();
+					}
+				}
+				ConfigHandler.writeBooleanConfig("toggles", "DungeonBossMusic", dungeonBossMusic);
+				player.addChatMessage(new ChatComponentText(DankersSkyblockMod.MAIN_COLOUR + "Custom dungeon boss music has been set to " + DankersSkyblockMod.SECONDARY_COLOUR + dungeonBossMusic + DankersSkyblockMod.MAIN_COLOUR + "."));
+				break;
 			case "list":
 				player.addChatMessage(new ChatComponentText(DankersSkyblockMod.TYPE_COLOUR + "Guild party notifications: " + DankersSkyblockMod.VALUE_COLOUR + gpartyToggled + "\n" +
 															DankersSkyblockMod.TYPE_COLOUR + " Coord/Angle display: " + DankersSkyblockMod.VALUE_COLOUR + coordsToggled + "\n" +
@@ -431,7 +447,8 @@ public class ToggleCommand extends CommandBase implements ICommand {
 															DankersSkyblockMod.TYPE_COLOUR + " Chronomatron solver: " + DankersSkyblockMod.VALUE_COLOUR + chronomatronToggled + "\n" +
 															DankersSkyblockMod.TYPE_COLOUR + " Superpairs solver: " + DankersSkyblockMod.VALUE_COLOUR + superpairsToggled + "\n" +
 															DankersSkyblockMod.TYPE_COLOUR + " Hide tooltips in experiment addons: " + DankersSkyblockMod.VALUE_COLOUR + hideTooltipsInExperimentAddonsToggled + "\n" +
-															DankersSkyblockMod.TYPE_COLOUR + " Auto-swap to pick block " + DankersSkyblockMod.VALUE_COLOUR + swapToPickBlockToggled 
+															DankersSkyblockMod.TYPE_COLOUR + " Auto-swap to pick block: " + DankersSkyblockMod.VALUE_COLOUR + swapToPickBlockToggled  + "\n" +
+															DankersSkyblockMod.TYPE_COLOUR + " Custom dungeon boss music: " + DankersSkyblockMod.VALUE_COLOUR + dungeonBossMusic
 				));
 				break;
 			default:
diff --git a/src/main/java/me/Danker/features/CustomMusic.java b/src/main/java/me/Danker/features/CustomMusic.java
new file mode 100644
index 0000000..8617e7b
--- /dev/null
+++ b/src/main/java/me/Danker/features/CustomMusic.java
@@ -0,0 +1,117 @@
+package me.Danker.features;
+
+import me.Danker.DankersSkyblockMod;
+import me.Danker.commands.ToggleCommand;
+import me.Danker.handlers.ScoreboardHandler;
+import me.Danker.utils.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.EntityPlayerSP;
+import net.minecraft.util.StringUtils;
+import net.minecraft.world.World;
+import net.minecraftforge.client.event.ClientChatReceivedEvent;
+import net.minecraftforge.client.event.sound.PlaySoundEvent;
+import net.minecraftforge.event.world.WorldEvent;
+import net.minecraftforge.fml.common.eventhandler.EventPriority;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
+
+import javax.sound.sampled.*;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+public class CustomMusic {
+
+    static boolean prevInDungeonBossRoom = false;
+    static boolean inDungeonBossRoom = false;
+    public static Clip dungeonboss;
+
+    @SubscribeEvent
+    public void onWorldChange(WorldEvent.Load event) {
+        reset();
+    }
+
+    @SubscribeEvent(priority = EventPriority.LOW)
+    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 % 10 == 0) {
+            if (ToggleCommand.dungeonBossMusic && Utils.inDungeons && world != null && player != null) {
+                prevInDungeonBossRoom = inDungeonBossRoom;
+                List<String> scoreboard = ScoreboardHandler.getSidebarLines();
+                if (scoreboard.size() > 2) {
+                    String firstLine = ScoreboardHandler.cleanSB(scoreboard.get(scoreboard.size() - 1));
+                    String secondLine = ScoreboardHandler.cleanSB(scoreboard.get(scoreboard.size() - 2));
+                    if (firstLine.contains("30,30") || // F1
+                        firstLine.contains("30,125") || // F2
+                        firstLine.contains("30,225") || // F3
+                        secondLine.contains("- Healthy") || // F3
+                        firstLine.contains("30,344") || // F4
+                        firstLine.contains("livid") || // F5
+                        firstLine.contains("sadan") || // F6
+                        firstLine.contains("necron")) { // F7
+
+                        inDungeonBossRoom = true;
+                        if (!prevInDungeonBossRoom && dungeonboss != null) {
+                            start();
+                        }
+                    } else {
+                        reset();
+                    }
+                }
+            }
+        }
+    }
+
+    @SubscribeEvent
+    public void onChat(ClientChatReceivedEvent event) {
+        if (!Utils.inDungeons) return;
+        String message = StringUtils.stripControlCodes(event.message.getUnformattedText());
+
+        if (message.contains("EXTRA STATS ")) {
+            if (dungeonboss != null) dungeonboss.stop();
+        }
+    }
+
+    @SubscribeEvent
+    public void onSound(PlaySoundEvent event) {
+        if (ToggleCommand.dungeonBossMusic && Utils.inDungeons && inDungeonBossRoom) {
+            if (event.name.startsWith("note.")) event.setCanceled(true);
+        }
+    }
+
+    public static void init(String configDirectory) throws IOException, LineUnavailableException, UnsupportedAudioFileException {
+        if (configDirectory == null) return;
+        File directory = new File(configDirectory + "\\dsmmusic");
+        if (!directory.exists()) directory.mkdir();
+
+        reset();
+
+        dungeonboss = AudioSystem.getClip();
+        File dungeonBossFile = new File(configDirectory + "\\dsmmusic\\dungeonboss.wav");
+        if (dungeonBossFile.exists()) {
+            AudioInputStream ais = AudioSystem.getAudioInputStream(dungeonBossFile);
+            dungeonboss.open(ais);
+
+            FloatControl volume = (FloatControl) dungeonboss.getControl(FloatControl.Type.MASTER_GAIN);
+            volume.setValue(-20F);
+        }
+    }
+
+    static void reset() {
+        inDungeonBossRoom = false;
+        if (dungeonboss != null) dungeonboss.stop();
+    }
+
+    public static void start() {
+        if (dungeonboss != null && inDungeonBossRoom) {
+            dungeonboss.setMicrosecondPosition(0);
+            dungeonboss.start();
+            dungeonboss.loop(Clip.LOOP_CONTINUOUSLY);
+        }
+    }
+
+}
diff --git a/src/main/java/me/Danker/gui/DankerGui.java b/src/main/java/me/Danker/gui/DankerGui.java
index a6d2bb1..2d07f27 100644
--- a/src/main/java/me/Danker/gui/DankerGui.java
+++ b/src/main/java/me/Danker/gui/DankerGui.java
@@ -2,6 +2,7 @@ package me.Danker.gui;
 
 import me.Danker.DankersSkyblockMod;
 import me.Danker.commands.ToggleCommand;
+import me.Danker.features.CustomMusic;
 import me.Danker.handlers.ConfigHandler;
 import me.Danker.handlers.TextRenderer;
 import me.Danker.utils.Utils;
@@ -46,6 +47,7 @@ public class DankerGui extends GuiScreen {
 	private GuiButton skill50Display;
 	private GuiButton outlineText;
 	private GuiButton cakeTimer;
+	private GuiButton dungeonBossMusic;
 	// Chat Messages
 	private GuiButton lividDagger;
 	private GuiButton sceptreMessages;
@@ -55,7 +57,7 @@ public class DankerGui extends GuiScreen {
 	private GuiButton cooldownMessages;
 	private GuiButton manaMessages;
 	private GuiButton killComboMessages;
-	//Dungeons
+	// Dungeons
 	private GuiButton dungeonTimer;
 	private GuiButton lowHealthNotify;
 	private GuiButton lividSolver;
@@ -138,6 +140,7 @@ public class DankerGui extends GuiScreen {
 		necronNotifications = new GuiButton(0, width / 2 - 100, (int) (height * 0.2), "Necron Phase Notifications: " + Utils.getColouredBoolean(ToggleCommand.necronNotificationsToggled));
 		bonzoTimer = new GuiButton(0, width / 2 - 100, (int) (height * 0.3), "Bonzo's Mask Timer: " + Utils.getColouredBoolean(ToggleCommand.bonzoTimerToggled));
 		autoSkillTracker = new GuiButton(0, width / 2 - 100, (int) (height * 0.4), "Auto Start/Stop Skill Tracker: " + Utils.getColouredBoolean(ToggleCommand.autoSkillTrackerToggled));
+		dungeonBossMusic = new GuiButton(0, width / 2 - 100, (int) (height * 0.5), "Custom Dungeon Boss Music: " + Utils.getColouredBoolean(ToggleCommand.dungeonBossMusic));
 
 		switch (page) {
 			case 1:
@@ -199,6 +202,7 @@ public class DankerGui extends GuiScreen {
         		this.buttonList.add(necronNotifications);
 				this.buttonList.add(bonzoTimer);
 				this.buttonList.add(autoSkillTracker);
+				this.buttonList.add(dungeonBossMusic);
 				this.buttonList.add(backPage);
 				break;
 		}
@@ -386,6 +390,17 @@ public class DankerGui extends GuiScreen {
 			ToggleCommand.killComboMessages = !ToggleCommand.killComboMessages;
 			ConfigHandler.writeBooleanConfig("toggles", "KillComboMessages", ToggleCommand.killComboMessages);
 			killComboMessages.displayString = "Kill Combo Messages: " + Utils.getColouredBoolean(ToggleCommand.killComboMessages);
+		} else if (button == dungeonBossMusic) {
+			ToggleCommand.dungeonBossMusic = !ToggleCommand.dungeonBossMusic;
+			if (CustomMusic.dungeonboss != null) {
+				if (ToggleCommand.dungeonBossMusic) {
+					CustomMusic.start();
+				} else {
+					CustomMusic.dungeonboss.stop();
+				}
+			}
+			ConfigHandler.writeBooleanConfig("toggles", "DungeonBossMusic", ToggleCommand.dungeonBossMusic);
+			dungeonBossMusic.displayString = "Custom Dungeon Boss Music: " + Utils.getColouredBoolean(ToggleCommand.dungeonBossMusic);
 		}
 	}
 	
diff --git a/src/main/java/me/Danker/handlers/ConfigHandler.java b/src/main/java/me/Danker/handlers/ConfigHandler.java
index cb04daa..6b17b3c 100644
--- a/src/main/java/me/Danker/handlers/ConfigHandler.java
+++ b/src/main/java/me/Danker/handlers/ConfigHandler.java
@@ -265,6 +265,8 @@ public class ConfigHandler {
 		ToggleCommand.chronomatronToggled = initBoolean("toggles", "Chronomatron", false);
 		ToggleCommand.superpairsToggled = initBoolean("toggles", "Superpairs", false);
 		ToggleCommand.hideTooltipsInExperimentAddonsToggled = initBoolean("toggles", "HideTooltipsInExperimentAddons", false);
+		// Custom Music
+		ToggleCommand.dungeonBossMusic = initBoolean("toggles", "DungeonBossMusic", false);
 
 		// API
 		if (!hasKey("api", "APIKey")) writeStringConfig("api", "APIKey", "");
-- 
cgit