JFrame openMonitorGUI(String title) {
    try {
      MonitorGUI gui = new MonitorGUI(this, title);

      JFrame frame = new JFrame(title);
      frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
      frame.addWindowListener(this);
      frame.getContentPane().add(gui);

      GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
      Rectangle r = ge.getMaximumWindowBounds();
      frame.setSize(400, 200);
      frame.setLocationRelativeTo(null);
      frame.pack();
      frame.setVisible(true);
      return frame;
    } catch (Exception e) {
      System.out.println("9\b" + getClass().getName() + "\n\t" + e);
      return null;
    }
  }
  public static void createAndShowGUI() {
    try {
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    } catch (ClassNotFoundException
        | InstantiationException
        | IllegalAccessException
        | UnsupportedLookAndFeelException ex) {
      ex.printStackTrace();
    }
    // UIManager.put("AuditoryCues.playList", UIManager.get("AuditoryCues.allAuditoryCues"));
    // UIManager.put("AuditoryCues.playList", UIManager.get("AuditoryCues.defaultCueList"));
    // UIManager.put("AuditoryCues.playList", UIManager.get("AuditoryCues.noAuditoryCues"));
    UIManager.put("AuditoryCues.playList", OPTION_PANE_AUDITORY_CUES);
    // UIManager.put("OptionPane.informationSound", "/example/notice2.wav");
    // UIManager.put("OptionPane.informationSound", "sounds/OptionPaneError.wav");
    // System.out.println(UIManager.get("AuditoryCues.actionMap"));

    JFrame frame = new JFrame("@title@");
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.getContentPane().add(new MainPanel());
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }
  ////////////// methods to create the interactive visualizer ////////////////////////
  private void createMainFrame() {
    mainFrame = new JFrame();
    mainFrame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
    Container contentPane = mainFrame.getContentPane();
    // contentPane.setLayout(new BorderLayout());

    // creates the control panel
    controlPanel = new JPanel(null);
    controlPanel.setLayout(new FlowLayout());
    makeSoundVis();
    mainFrame.addComponentListener(new ResizeHandler());

    // setting up the play sound button
    playBtn = new JButton("Play");
    playBtn.setEnabled(true);
    playBtn.setToolTipText("Play the  sound");
    playBtn.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent event) {
            stopBtn.setEnabled(true);
            pauseBtn.setEnabled(true);
            playBtn.setEnabled(false);
            playSelectionBtn.setEnabled(false);
            zoomInBtn.setEnabled(false);
            zoomOutBtn.setEnabled(false);
            isPlaying = true;
            myHelper.play();
          }
        });
    controlPanel.add(playBtn);

    // setting up the play selection button
    playSelectionBtn = new JButton("Play Selection");
    playSelectionBtn.setEnabled(false);
    playSelectionBtn.setToolTipText("Play sound between start and stop index");
    playSelectionBtn.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent event) {
            playSelClicked++;
            stopBtn.setEnabled(true);
            pauseBtn.setEnabled(true);
            playSelectionBtn.setEnabled(false);
            playBtn.setEnabled(false);
            zoomInBtn.setEnabled(false);
            zoomOutBtn.setEnabled(false);
            isPlaying = false;
            if (playSelClicked == 1) {
              myHelper.playInRange(
                  wavePanel.getSelectionStartSample(), wavePanel.getSelectionEndSample());
            } else {
              myHelper.play();
            }
          }
        });
    controlPanel.add(playSelectionBtn);

    // setting up the stop button
    stopBtn = new JButton("Stop");
    stopBtn.setEnabled(false);
    stopBtn.setToolTipText("Stop playing the sound");
    stopBtn.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent event) {
            myHelper.stop();
            stopBtn.setEnabled(false);
            pauseBtn.setEnabled(false);
            playBtn.setEnabled(true);
            if (wavePanel.moreZoomInScope()) {
              zoomInBtn.setEnabled(true);
              playSelectionBtn.setEnabled(true);
            }

            if (wavePanel.moreZoomOutScope()) {
              zoomOutBtn.setEnabled(true);
            }
            playSelClicked = 0;
            isPlaying = false;
          }
        });
    controlPanel.add(stopBtn);

    // setting up the stop button
    pauseBtn = new JButton("Pause");
    pauseBtn.setEnabled(false);
    pauseBtn.setToolTipText("Pause the sound");
    pauseBtn.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent event) {
            myHelper.pause();
            if (isPlaying) {
              playBtn.setEnabled(true);
            } else {
              playSelectionBtn.setEnabled(true);
            }
          }
        });
    controlPanel.add(pauseBtn);

    // setting up the zoom  button
    zoomInBtn = new JButton("Zoom In");
    zoomInBtn.setEnabled(false);
    zoomInBtn.setToolTipText("Click to see the samples within your selection");
    zoomInBtn.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent event) {
            handleZoomIn();
          }
        });
    controlPanel.add(zoomInBtn);

    // setting up the zoom  button
    zoomOutBtn = new JButton("Zoom Out");
    zoomOutBtn.setEnabled(false);
    zoomOutBtn.setToolTipText("Click to zoom out");
    zoomOutBtn.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent event) {
            handleZoomOut();
          }
        });
    controlPanel.add(zoomOutBtn);

    controlPanel.setBounds(0, controlLocY, frameWidth, controlHeight);
    contentPane.add(controlPanel);

    contentPane.add(wavePanel);
    contentPane.add(overViewPanel);
    wavePanel.setBounds(0, waveLocY, frameWidth, waveHeight);

    // controlPanel.removeAll();
    // controlPanel.setBackground(Color.CYAN);

    mainFrame.setSize(frameWidth, frameHeight);

    overViewPanel.init();
    wavePanel.init();
    //
    // mainFrame.pack();
    // mainFrame.setResizable(false);
    // mainFrame.validate();

    mainFrame.setVisible(true);
    overViewPanel.setBounds(0, 0, frameWidth, overViewHeight);

    // mainFrame.validate();

  }
public class HotSMain extends JPanel
    implements ActionListener, MouseListener, MouseMotionListener, KeyListener {

  // General
  private int scene = OVERWORLD;
  private static int TITLE = 0;
  private static int PROLOGUE = 1;
  private static int OVERWORLD = 2;
  private static int MENU = 3;
  private static int BATTLE = 4;

  private Player player;
  ArrayList<Ally> allies = new ArrayList<Ally>();
  ArrayList<Enemy> enemies = new ArrayList<Enemy>();
  private JFrame frame = new JFrame();
  private Container canvas = frame.getContentPane();
  private Image background;
  private int mX;
  private int mY;

  // Overworld
  private boolean moveUp = false;
  private boolean moveDown = false;
  private boolean moveLeft = false;
  private boolean moveRight = false;
  private Timer moveTimer = new Timer(10, this);

  private JPanel menuScreen = new JPanel();
  private ArrayList<JButton> menuButtons = new ArrayList<JButton>();
  private JButton itemsButton = new JButton("Items");
  private JButton equipButton = new JButton("Equip");
  private JButton skillsButton = new JButton("Skills");
  private JButton statusButton = new JButton("Status");
  private JButton settingsButton = new JButton("Settings");
  private JButton dataButton = new JButton("Data");

  // Battle
  private int battleBG;
  private Timer staminaTimer = new Timer(100, this);
  ArrayList<Spell> spellsThrown = new ArrayList<Spell>();
  private Rectangle kickDirt = new Rectangle(20, 500, 130, 30);
  private Rectangle hurlPebble = new Rectangle(20, 540, 130, 30);
  private boolean battleWon;
  private boolean battleLost;
  private int totalExperience = 0;
  private boolean nextWindow = false;

  public HotSMain() {
    // General
    setPreferredSize(new Dimension(800, 600));
    canvas.add(this);
    setBackground(Color.GRAY);
    frame.setResizable(false);
    frame.setTitle("Heroes of the Forest");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    // Overworld
    menuScreen.setPreferredSize(new Dimension(800, 150));
    menuScreen.setBackground(Color.DARK_GRAY);
    menuScreen.setVisible(false);

    menuButtons.add(itemsButton);
    menuButtons.add(equipButton);
    menuButtons.add(skillsButton);
    menuButtons.add(statusButton);
    menuButtons.add(settingsButton);
    menuButtons.add(dataButton);

    for (JButton button : menuButtons) {
      menuScreen.add(button);
      button.addActionListener(this);
    }

    canvas.add(menuScreen, BorderLayout.SOUTH);
    ImageIcon bg = new ImageIcon("OverworldBG.jpg");
    background = bg.getImage();

    frame.pack();
    frame.setVisible(true);
    player = new Player();
    enemies.add(new Stalker(375, 200));
    player.defaultPlayer();
    frame.addKeyListener(this);
    frame.addMouseListener(this);
    frame.addMouseMotionListener(this);
    moveTimer.start();
  }

  public void actionPerformed(ActionEvent a) {
    Object source = a.getSource();

    if (scene == OVERWORLD) {
      if (source == moveTimer) {
        if (moveUp && !moveDown) player.moveUp();
        else if (!moveUp && moveDown) player.moveDown();

        if (moveLeft && !moveRight) player.moveLeft();
        else if (!moveLeft && moveRight) player.moveRight();
      }

      if (source == itemsButton) itemsButton.setText("ITEMS!");
      else if (source == equipButton) equipButton.setText("EQUIPMENT!");
      else if (source == skillsButton) skillsButton.setText("SKILLS");
      else if (source == settingsButton) settingsButton.setText("SETTINGS");
      else if (source == statusButton) statusButton.setText("STATUS");
      else if (source == dataButton) dataButton.setText("DATA");
    }
    if (scene == BATTLE) {
      if (source == moveTimer) {
        // Spell Movement
        for (int spellNum = 0; spellNum < spellsThrown.size(); spellNum++) {
          Spell spell = spellsThrown.get(spellNum);
          spell.move();
          if (spell.spellHit()) {
            enemies.get(spell.getTarget()).takeDamage(spell.getDamage());
            enemies.get(spell.getTarget()).statusPresent(spell.getEffect());
            spellsThrown.remove(spellNum);
            checkEnemyPresence();
          }
        }

        for (int enemyLoop = 0; enemyLoop < enemies.size(); enemyLoop++) {
          Enemy enemy = enemies.get(enemyLoop);
          for (int spellNum = 0; spellNum < enemy.spellsThrown.size(); spellNum++) {
            Spell spell = enemy.spellsThrown.get(spellNum);
            spell.move();
            if (spell.spellHit()) {
              player.takeDamage(spell.getDamage());
              enemy.spellsThrown.remove(spellNum);
              checkAllyPresence();
            }
          }
        }
      }
      if (source == staminaTimer) {
        // Stamina Regeneration
        player.staminaGain(16);
        // Enemy Attacks
        int enemyLoop;
        for (enemyLoop = 0; enemyLoop < enemies.size(); enemyLoop++) {
          enemies.get(enemyLoop).attack(player.centerX(), player.centerY(), 12);
        }
      }
    }
    repaint();

    // To check collision
    if (scene == OVERWORLD) {
      for (int loop = 0; loop < enemies.size(); loop++) {
        Enemy enemy = enemies.get(loop);
        if (enemy.hitbox().intersects(player.hitbox())) {
          player.combatChange(true);
          enemy.combatChange(true);
          battleBegin();
        }
      }
    }
  }

  public void mouseDragged(MouseEvent e) {}

  public void mouseMoved(MouseEvent e) {
    mX = e.getX();
    mY = e.getY();
  }

  public void mouseClicked(MouseEvent e) {
    if (scene == BATTLE) {
      if (!battleWon) {
        int target = 0;
        if (kickDirt.contains(mX, mY) && player.getStamina() >= 33.3 && !player.getDeath()) {
          spellsThrown.add(
              new Spell(
                  0,
                  new Color(153, 76, 0),
                  player.centerX(),
                  player.centerY(),
                  enemies.get(target).centerX(),
                  enemies.get(target).centerY(),
                  target));
          player.staminaGain(-333);
        }
        if (hurlPebble.contains(mX, mY) && player.getStamina() >= 100 && !player.getDeath()) {
          spellsThrown.add(
              new Spell(
                  1,
                  Color.LIGHT_GRAY,
                  player.centerX(),
                  player.centerY(),
                  enemies.get(target).centerX(),
                  enemies.get(target).centerY(),
                  target));
          player.staminaGain(-1000);
        }
      }
    }
  }

  public void mousePressed(MouseEvent e) {}

  // Hotkeys!
  public void keyPressed(KeyEvent e) {
    int keyID = e.getKeyCode();

    if (scene == OVERWORLD) {
      if (keyID == KeyEvent.VK_UP || keyID == KeyEvent.VK_W) {
        moveUp = true;
      }
      if (keyID == KeyEvent.VK_DOWN || keyID == KeyEvent.VK_S) {
        moveDown = true;
      }
      if (keyID == KeyEvent.VK_LEFT || keyID == KeyEvent.VK_A) {
        moveLeft = true;
      }
      if (keyID == KeyEvent.VK_RIGHT || keyID == KeyEvent.VK_D) {
        moveRight = true;
      }

      if (keyID == KeyEvent.VK_ENTER) {
        // Toggle the visible state of the Game Menu
        Boolean visibleState = menuScreen.isVisible();
        menuScreen.setVisible(!visibleState);
      }

      for (int enemyNum = 0; enemyNum < enemies.size(); enemyNum++) {
        Enemy enemy = enemies.get(enemyNum);
        if (enemy.hitbox().intersects(player.hitbox())) {
          player.combatChange(true);
          enemy.combatChange(true);
          battleBegin();
        }
      }
    } else if (scene == BATTLE) {
      if (keyID == KeyEvent.VK_SPACE
          && player.getStamina() >= 33.3
          && !player.getDeath()
          && !battleWon) {
        int target = 0;
        spellsThrown.add(
            new Spell(
                0,
                new Color(153, 76, 0),
                player.centerX(),
                player.centerY(),
                enemies.get(target).centerX(),
                enemies.get(target).centerY(),
                target));
        player.staminaGain(-333);
      }
      if (keyID == KeyEvent.VK_ENTER
          && player.getStamina() == 100
          && !player.getDeath()
          && !battleWon) {
        int target = 0;
        spellsThrown.add(
            new Spell(
                1,
                Color.LIGHT_GRAY,
                player.centerX(),
                player.centerY(),
                enemies.get(target).centerX(),
                enemies.get(target).centerY(),
                target));
        player.staminaGain(-1000);
      }
      if ((keyID == KeyEvent.VK_ENTER || keyID == KeyEvent.VK_SPACE) && battleWon) {
        if (player.levelUp()) {
          nextWindow = true;
        } else {
          battleEnd();
        }
      }
    }
    repaint();
  }

  public void keyReleased(KeyEvent e) {
    int keyID = e.getKeyCode();

    if (scene == OVERWORLD) {
      if (keyID == KeyEvent.VK_UP || keyID == KeyEvent.VK_W) {
        moveUp = false;
      }
      if (keyID == KeyEvent.VK_DOWN || keyID == KeyEvent.VK_S) {
        moveDown = false;
      }
      if (keyID == KeyEvent.VK_LEFT || keyID == KeyEvent.VK_A) {
        moveLeft = false;
      }
      if (keyID == KeyEvent.VK_RIGHT || keyID == KeyEvent.VK_D) {
        moveRight = false;
      }
    }
  }

  // Transitions from Overworld to Battle scene
  public void battleBegin() {
    scene = BATTLE;
    moveUp = false;
    moveDown = false;
    moveLeft = false;
    moveRight = false;

    // Background changer
    int bgSelector = (int) (10 * Math.random() + 1);
    if (bgSelector > 5) {
      ImageIcon bg = new ImageIcon("BattleBG1.jpg");
      background = bg.getImage();
      battleBG = 1;
      player.battleBegin(235, 380);
      int placed = 0;
      for (int enemyNum = 0; enemyNum < enemies.size(); enemyNum++) {
        Enemy enemy = enemies.get(enemyNum);
        if (enemy.getActivity()) {
          enemy.battleBegin(440 - 20 * placed, 125);
          placed++;
          totalExperience += enemy.getEXP();
        }
      }
    } else {
      ImageIcon bg = new ImageIcon("BattleBG2.png");
      background = bg.getImage();
      battleBG = 2;
      player.battleBegin(650, 365);
      int placed = 0;
      for (int loop = 0; loop < enemies.size(); loop++) {
        if (enemies.get(loop).getActivity()) {
          enemies.get(loop).battleBegin(340 - 20 * placed, 145);
          placed++;
          totalExperience += enemies.get(loop).getEXP();
        }
      }
    }
    menuScreen.setVisible(false);
    staminaTimer.start();
  }

  // Draws the Battle Menu
  public void drawMenu(Graphics g) {
    if (scene == BATTLE) {
      // Background
      g.setColor(new Color(0, 100, 0));
      g.fillRect(0, 450, 800, 150);
      g.setColor(Color.BLACK);
      g.fillRect(10, 460, 780, 130);

      // Player
      // Health
      g.setColor(Color.WHITE);
      g.setFont(new Font("Bell MT", Font.BOLD, 20));
      FontMetrics metrics = g.getFontMetrics(new Font("Bell MT", Font.BOLD, 20));
      int hgt = metrics.getHeight();
      // Hgt = 26
      int adv = metrics.stringWidth(player.getHealth() + "/" + player.getMaxHealth(0));
      g.setColor(Color.DARK_GRAY);
      g.fillRect(getWidth() - 170, 470, 150, hgt - 6);
      if ((double) player.getHealth() / player.getMaxHealth(0) > .25) g.setColor(Color.RED);
      else g.setColor(player.getLowHealth());
      g.drawString(
          player.getHealth() + "/" + player.getMaxHealth(0), getWidth() - adv - 180, 461 + hgt);
      g.fillRect(
          getWidth() - 167,
          473,
          (int) (144 * player.getHealth() / player.getMaxHealth(0)),
          hgt - 12);

      // Stamina
      g.setColor(Color.DARK_GRAY);
      g.fillRect(getWidth() - 170, 500, 150, hgt - 6);
      adv = metrics.stringWidth((int) player.getStamina() + "%");
      if (player.getStamina() < 33.3) g.setColor(Color.WHITE);
      else if (player.getStamina() == 100) g.setColor(Color.GREEN);
      else g.setColor(Color.CYAN);

      g.drawString((int) player.getStamina() + "%", getWidth() - adv - 180, 491 + hgt);
      g.fillRect(getWidth() - 167, 503, (int) (144 * player.getStamina() / 100), hgt - 12);

      // Basic Attack
      adv = metrics.stringWidth("Kick Dirt");
      g.setColor(Color.DARK_GRAY);
      g.fillRect(20, 470, adv + 10, 30);
      g.setColor(Color.WHITE);
      g.drawString("Kick Dirt", 25, 492);

      // Spell 1
      adv = metrics.stringWidth("Hurl Pebble");
      g.setColor(Color.DARK_GRAY);
      g.fillRect(20, 510, adv + 10, 30);
      g.setColor(Color.WHITE);
      g.drawString("Hurl Pebble", 25, 532);
    }
  }

  public void checkEnemyPresence() {
    if (scene == BATTLE) {
      int loop;
      int deadCounter = 0;
      for (loop = 0; loop < enemies.size(); loop++) {
        if (enemies.get(loop).getDeath()) deadCounter++;
      }
      if (deadCounter == enemies.size()) {
        victory();
      }
    }
  }

  public void checkAllyPresence() {
    if (scene == BATTLE) {
      // int loop;
      int deadCounter = 0;
      if (player.getDeath()) deadCounter++;
      /*for (loop = 0; loop < allies.size(); loop++){
      	if (allies.get(loop).getDeath())
      		deadCounter++;
      }*/
      if (deadCounter == allies.size() + 1) defeat();
    }
  }

  public void victory() {
    battleWon = true;
    player.expGain(totalExperience);
    enemies.removeAll(enemies);
    spellsThrown.removeAll(spellsThrown);
    staminaTimer.stop();
  }

  public void defeat() {
    battleLost = true;
    staminaTimer.stop();
    int loop;
    for (loop = 0; loop < enemies.size(); loop++) {
      enemies.get(loop).spellsThrown.removeAll(spellsThrown);
    }
  }

  public void drawVictory(Graphics g) {
    g.setColor(new Color(0, 0, 0, 200));
    g.fillRect(195, 220, 410, 110);
    g.setColor(new Color(255, 255, 255, 200));
    g.fillRect(200, 225, 400, 100);
    g.setColor(new Color(0, 0, 0, 200));
    g.setFont(new Font("Bell MT", Font.BOLD, 20));
    FontMetrics metrics = g.getFontMetrics(new Font("Bell MT", Font.BOLD, 20));
    int hgt = metrics.getHeight();

    String initialMessage;
    String followupMessage;

    if (nextWindow) {
      initialMessage = "You have gotten stronger.";
      followupMessage = player.getName() + " is now level " + player.getLevel() + "!";
    } else {
      initialMessage = "You survived!";
      followupMessage = "You and your allies gain " + totalExperience + " experience!";
    }

    // Hgt = 26
    int adv = metrics.stringWidth(initialMessage);
    g.drawString(initialMessage, getWidth() / 2 - adv / 2, 234 + hgt);
    adv = metrics.stringWidth(followupMessage);
    g.drawString(followupMessage, getWidth() / 2 - adv / 2, 269 + hgt);
  }

  public void drawDefeat(Graphics g) {
    g.setColor(new Color(0, 0, 0, 200));
    g.fillRect(195, 220, 410, 110);
    g.setColor(new Color(255, 255, 255, 200));
    g.fillRect(200, 225, 400, 100);
    g.setColor(new Color(0, 0, 0, 200));
    g.setFont(new Font("Bell MT", Font.BOLD, 20));
    FontMetrics metrics = g.getFontMetrics(new Font("Bell MT", Font.BOLD, 20));
    int hgt = metrics.getHeight();
    // Hgt = 26
    int adv = metrics.stringWidth("You all fainted.");
    g.drawString("You all fainted.", getWidth() / 2 - adv / 2, 234 + hgt);
    adv = metrics.stringWidth("Defenseless, you are all eaten.");
    g.drawString("Defenseless, you are all eaten.", getWidth() / 2 - adv / 2, 269 + hgt);
  }

  public void battleEnd() {
    scene = OVERWORLD;
    ImageIcon bg = new ImageIcon("OverworldBG.jpg");
    background = bg.getImage();
    player.battleEnd();
    totalExperience = 0;
    nextWindow = false;
    battleWon = false;

    enemies.add(new Stalker(175, 200));
  }

  public void keyTyped(KeyEvent e) {}

  public void mouseEntered(MouseEvent e) {}

  public void mouseExited(MouseEvent e) {}

  public void mouseReleased(MouseEvent e) {}

  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    if (scene == OVERWORLD) g.drawImage(background, 0, 0, this);
    if (scene == BATTLE) {
      if (battleBG == 1) g.drawImage(background, 0, -130, this);
      else g.drawImage(background, 0, 0, this);
    }
    int loop;
    for (loop = 0; loop < enemies.size(); loop++) {
      if (scene == OVERWORLD) {
        enemies.get(loop).drawEnemy(g);
      }
      if (scene == BATTLE) {
        if (enemies.get(loop).getActivity()) {
          enemies.get(loop).drawEnemy(g);
        }
      }
    }
    for (loop = 0; loop < spellsThrown.size(); loop++) {
      spellsThrown.get(loop).drawSpell(g);
    }
    player.drawPlayer(g);
    for (loop = 0; loop < enemies.size(); loop++) {
      enemies.get(loop).drawSpells(g);
    }
    if (scene == BATTLE) {
      drawMenu(g);
      if (battleWon) drawVictory(g);
      else if (battleLost) drawDefeat(g);
    }
  }

  public static void main(String[] args) {
    new HotSMain();
  }
}