Code Sketch


Bixuu MysticPortalExpeditionEvent7
By: Mhalsakant School
Category: Programming
import java.awt.{BasicStroke, BorderLayout, CardLayout, Color, Dimension, Font, GradientPaint, Graphics, Graphics2D, RenderingHints}
import java.awt.event.{ActionEvent, ActionListener, KeyAdapter, KeyEvent, MouseAdapter, MouseEvent, WindowAdapter, WindowEvent}
import java.awt.geom.Ellipse2D
import javax.swing.{BorderFactory, JButton, JFrame, JLabel, JOptionPane, JPanel, JTextField, SwingConstants, SwingUtilities, Timer, WindowConstants}
import scala.collection.mutable.ArrayBuffer

object MysticPortalExpeditionEvent7 {
  private val frameTitle = "INFINITY REALMS SEASON 07 - MYSTIC PORTAL EXPEDITION"

  def main(args: Array[String]): Unit = {
    SwingUtilities.invokeLater(new Runnable {
      def run(): Unit = {
        val frame = new JFrame(frameTitle)
        frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE)
        frame.setSize(1080, 720)
        frame.setMinimumSize(new Dimension(900, 620))
        frame.setLocationRelativeTo(null)

        val cardLayout = new CardLayout()
        val root = new JPanel(cardLayout)
        root.setBackground(new Color(9, 13, 31))

        val loginPanel = new JPanel(new BorderLayout())
        loginPanel.setBackground(new Color(12, 17, 42))
        loginPanel.setBorder(BorderFactory.createEmptyBorder(35, 70, 35, 70))

        val title = new JLabel("MYSTIC PORTAL EXPEDITION", SwingConstants.CENTER)
        title.setForeground(new Color(190, 225, 255))
        title.setFont(new Font("Dialog", Font.BOLD, 32))

        val subtitle = new JLabel("INFINITY REALMS SEASON 07  |  EXPLORE THE UNKNOWN", SwingConstants.CENTER)
        subtitle.setForeground(new Color(152, 177, 220))
        subtitle.setFont(new Font("Dialog", Font.BOLD, 15))

        val centre = new JPanel()
        centre.setOpaque(false)
        centre.setLayout(new javax.swing.BoxLayout(centre, javax.swing.BoxLayout.Y_AXIS))

        val story = new JLabel("Three worlds are sealed. Find the runes, awaken the portals, and discover the lost realm.", SwingConstants.CENTER)
        story.setForeground(new Color(220, 230, 255))
        story.setFont(new Font("Dialog", Font.PLAIN, 15))
        story.setAlignmentX(0.5f)

        val nameLabel = new JLabel("ENTER YOUR EXPLORER NAME", SwingConstants.CENTER)
        nameLabel.setForeground(new Color(150, 230, 220))
        nameLabel.setFont(new Font("Dialog", Font.BOLD, 14))
        nameLabel.setAlignmentX(0.5f)

        val nameField = new JTextField("Explorer")
        nameField.setFont(new Font("Dialog", Font.PLAIN, 18))
        nameField.setHorizontalAlignment(SwingConstants.CENTER)
        nameField.setMaximumSize(new Dimension(330, 42))
        nameField.setAlignmentX(0.5f)
        nameField.setBackground(new Color(25, 34, 66))
        nameField.setForeground(Color.WHITE)
        nameField.setCaretColor(Color.WHITE)
        nameField.setBorder(BorderFactory.createCompoundBorder(
          BorderFactory.createLineBorder(new Color(94, 180, 220), 2),
          BorderFactory.createEmptyBorder(7, 12, 7, 12)
        ))

        val startButton = new JButton("START EXPEDITION")
        startButton.setFont(new Font("Dialog", Font.BOLD, 17))
        startButton.setForeground(Color.WHITE)
        startButton.setBackground(new Color(42, 116, 145))
        startButton.setFocusPainted(false)
        startButton.setAlignmentX(0.5f)
        startButton.setMaximumSize(new Dimension(260, 48))

        val controls = new JLabel("WASD / ARROWS: MOVE     CLICK: WALK     E: INTERACT     SPACE: MYSTIC DASH     Q: AURA", SwingConstants.CENTER)
        controls.setForeground(new Color(145, 160, 200))
        controls.setFont(new Font("Dialog", Font.PLAIN, 12))
        controls.setAlignmentX(0.5f)

        centre.add(javax.swing.Box.createVerticalGlue())
        centre.add(story)
        centre.add(javax.swing.Box.createVerticalStrut(35))
        centre.add(nameLabel)
        centre.add(javax.swing.Box.createVerticalStrut(10))
        centre.add(nameField)
        centre.add(javax.swing.Box.createVerticalStrut(22))
        centre.add(startButton)
        centre.add(javax.swing.Box.createVerticalStrut(35))
        centre.add(controls)
        centre.add(javax.swing.Box.createVerticalGlue())

        val headingPanel = new JPanel(new BorderLayout())
        headingPanel.setOpaque(false)
        headingPanel.add(title, BorderLayout.CENTER)
        headingPanel.add(subtitle, BorderLayout.SOUTH)
        loginPanel.add(headingPanel, BorderLayout.NORTH)
        loginPanel.add(centre, BorderLayout.CENTER)

        root.add(loginPanel, "login")
        frame.setContentPane(root)

        var currentGame: MysticGamePanel = null
        startButton.addActionListener(new ActionListener {
          def actionPerformed(e: ActionEvent): Unit = {
            val playerName = nameField.getText.trim
            if (playerName.length == 0) {
              JOptionPane.showMessageDialog(frame, "Please enter your explorer name.", "Explorer Name", JOptionPane.INFORMATION_MESSAGE)
            } else {
              if (currentGame != null) currentGame.stopGame()
              currentGame = new MysticGamePanel(playerName)
              root.add(currentGame, "game")
              cardLayout.show(root, "game")
              currentGame.startGame()
              currentGame.requestFocusInWindow()
            }
          }
        })

        frame.addWindowListener(new WindowAdapter {
          override def windowClosing(e: WindowEvent): Unit = {
            if (currentGame != null) currentGame.stopGame()
          }
        })

        frame.setVisible(true)
        nameField.requestFocusInWindow()
      }
    })
  }
}

class MysticGamePanel(playerName: String) extends JPanel {
  private case class Relic(var x: Int, var y: Int, var collected: Boolean)
  private val realmNames = Array("Whispering Grove", "Astral Library", "Crystal Caverns")
  private val realmDescriptions = Array(
    "Ancient trees hide the first portal runes.",
    "Floating books guard the memory seals.",
    "The final crystals wait beneath the mountain."
  )
  private val relics = ArrayBuffer[Relic]()
  private var realmIndex = 0
  private var explorerX = 105.0
  private var explorerY = 345.0
  private var moveUp = false
  private var moveDown = false
  private var moveLeft = false
  private var moveRight = false
  private var mouseTargetActive = false
  private var mouseTargetX = 0.0
  private var mouseTargetY = 0.0
  private var totalRelics = 0
  private var energy = 55
  private var dashTicks = 0
  private var shieldTicks = 0
  private var damageCooldown = 0
  private var message = "Find the glowing relics. Bring their energy to the portal."
  private var messageTicks = 300
  private var hasWon = false
  private var tickCount = 0
  private var wispOneX = 500.0
  private var wispOneY = 210.0
  private var wispTwoX = 720.0
  private var wispTwoY = 430.0
  private val panelWidth = 1080
  private val panelHeight = 720
  private val portalX = 930.0
  private val portalY = 350.0

  setPreferredSize(new Dimension(panelWidth, panelHeight))
  setFocusable(true)
  setDoubleBuffered(true)
  setBackground(new Color(10, 16, 38))

  private def loadRelics(): Unit = {
    relics.clear()
    relics += Relic(220, 170, false)
    relics += Relic(390, 290, false)
    relics += Relic(570, 160, false)
    relics += Relic(720, 475, false)
    relics += Relic(475, 520, false)
  }

  loadRelics()

  private val gameTimer = new Timer(16, new ActionListener {
    def actionPerformed(e: ActionEvent): Unit = updateGame()
  })

  addKeyListener(new KeyAdapter {
    override def keyPressed(e: KeyEvent): Unit = {
      e.getKeyCode match {
        case KeyEvent.VK_W | KeyEvent.VK_UP => moveUp = true; mouseTargetActive = false
        case KeyEvent.VK_S | KeyEvent.VK_DOWN => moveDown = true; mouseTargetActive = false
        case KeyEvent.VK_A | KeyEvent.VK_LEFT => moveLeft = true; mouseTargetActive = false
        case KeyEvent.VK_D | KeyEvent.VK_RIGHT => moveRight = true; mouseTargetActive = false
        case KeyEvent.VK_E => interact()
        case KeyEvent.VK_SPACE => useDash()
        case KeyEvent.VK_Q => useAura()
        case KeyEvent.VK_P => togglePause()
        case KeyEvent.VK_B => showExitMessage()
        case _ =>
      }
    }

    override def keyReleased(e: KeyEvent): Unit = {
      e.getKeyCode match {
        case KeyEvent.VK_W | KeyEvent.VK_UP => moveUp = false
        case KeyEvent.VK_S | KeyEvent.VK_DOWN => moveDown = false
        case KeyEvent.VK_A | KeyEvent.VK_LEFT => moveLeft = false
        case KeyEvent.VK_D | KeyEvent.VK_RIGHT => moveRight = false
        case _ =>
      }
    }
  })

  addMouseListener(new MouseAdapter {
    override def mousePressed(e: MouseEvent): Unit = {
      if (!hasWon && e.getButton == MouseEvent.BUTTON1) {
        mouseTargetX = e.getX.toDouble
        mouseTargetY = e.getY.toDouble
        mouseTargetActive = true
        requestFocusInWindow()
      }
    }
  })

  def startGame(): Unit = {
    if (!gameTimer.isRunning) gameTimer.start()
    requestFocusInWindow()
  }

  def stopGame(): Unit = {
    if (gameTimer.isRunning) gameTimer.stop()
  }

  private def setMessage(text: String): Unit = {
    message = text
    messageTicks = 240
  }

  private def collectedHere: Int = {
    var count = 0
    var i = 0
    while (i < relics.length) {
      if (relics(i).collected) count += 1
      i += 1
    }
    count
  }

  private def movePlayer(dx: Double, dy: Double): Unit = {
    val length = math.sqrt(dx * dx + dy * dy)
    if (length > 0.001) {
      val speedBonus = math.min(1.5, totalRelics.toDouble * 0.08)
      val speed = 3.6 + speedBonus
      explorerX += (dx / length) * speed
      explorerY += (dy / length) * speed
    }
    explorerX = math.max(55.0, math.min(1015.0, explorerX))
    explorerY = math.max(115.0, math.min(655.0, explorerY))
  }

  private def updateGame(): Unit = {
    if (!hasWon) {
      tickCount += 1
      if (messageTicks > 0) messageTicks -= 1
      if (dashTicks > 0) dashTicks -= 1
      if (shieldTicks > 0) shieldTicks -= 1
      if (damageCooldown > 0) damageCooldown -= 1

      var dx = 0.0
      var dy = 0.0
      if (moveLeft) dx -= 1.0
      if (moveRight) dx += 1.0
      if (moveUp) dy -= 1.0
      if (moveDown) dy += 1.0

      if (dx != 0.0 || dy != 0.0) {
        mouseTargetActive = false
        movePlayer(dx, dy)
      } else if (mouseTargetActive) {
        val tx = mouseTargetX - explorerX
        val ty = mouseTargetY - explorerY
        val distance = math.sqrt(tx * tx + ty * ty)
        if (distance < 9.0) mouseTargetActive = false
        else movePlayer(tx, ty)
      }

      wispOneX = 500.0 + math.sin(tickCount.toDouble * 0.025) * 115.0
      wispOneY = 215.0 + math.cos(tickCount.toDouble * 0.018) * 65.0
      wispTwoX = 700.0 + math.cos(tickCount.toDouble * 0.021) * 95.0
      wispTwoY = 430.0 + math.sin(tickCount.toDouble * 0.017) * 55.0

      if (damageCooldown == 0 && shieldTicks == 0 && (distanceTo(explorerX, explorerY, wispOneX, wispOneY) < 29.0 || distanceTo(explorerX, explorerY, wispTwoX, wispTwoY) < 29.0)) {
        energy = math.max(0, energy - 8)
        damageCooldown = 65
        setMessage("A Shadow Wisp drained your energy! Use Q for an Aura Shield.")
      }
      repaint()
    }
  }

  private def distanceTo(x1: Double, y1: Double, x2: Double, y2: Double): Double = {
    val dx = x1 - x2
    val dy = y1 - y2
    math.sqrt(dx * dx + dy * dy)
  }

  private def interact(): Unit = {
    if (hasWon) return
    var nearestIndex = -1
    var nearestDistance = 99999.0
    var i = 0
    while (i < relics.length) {
      val relic = relics(i)
      if (!relic.collected) {
        val d = distanceTo(explorerX, explorerY, relic.x.toDouble, relic.y.toDouble)
        if (d < nearestDistance) {
          nearestDistance = d
          nearestIndex = i
        }
      }
      i += 1
    }

    if (nearestIndex >= 0 && nearestDistance < 52.0) {
      relics(nearestIndex).collected = true
      totalRelics += 1
      energy = math.min(100, energy + 18)
      setMessage("Relic collected! Energy restored. " + collectedHere.toString + "/5 in this realm.")
    } else if (distanceTo(explorerX, explorerY, portalX, portalY) < 82.0) {
      if (collectedHere >= 5) {
        if (realmIndex < 2) {
          realmIndex += 1
          explorerX = 105.0
          explorerY = 345.0
          energy = math.min(100, energy + 25)
          loadRelics()
          setMessage("Portal opened! Welcome to " + realmNames(realmIndex) + ".")
        } else {
          hasWon = true
          stopGame()
          repaint()
          JOptionPane.showMessageDialog(this, "The Mystic Nexus is restored!\nExplorer: " + playerName + "\nRelics found: " + totalRelics.toString, "EXPEDITION COMPLETE", JOptionPane.INFORMATION_MESSAGE)
        }
      } else {
        setMessage("The portal is sealed. Collect all 5 relics in this realm first.")
      }
    } else {
      setMessage("Move close to a glowing relic or the portal, then press E.")
    }
    repaint()
  }

  private def useDash(): Unit = {
    if (hasWon) return
    if (energy >= 12 && dashTicks == 0) {
      val dx = (if (moveRight) 1.0 else 0.0) - (if (moveLeft) 1.0 else 0.0)
      val dy = (if (moveDown) 1.0 else 0.0) - (if (moveUp) 1.0 else 0.0)
      var dashX = dx
      var dashY = dy
      if (dashX == 0.0 && dashY == 0.0 && mouseTargetActive) {
        dashX = mouseTargetX - explorerX
        dashY = mouseTargetY - explorerY
      }
      if (dashX == 0.0 && dashY == 0.0) dashX = 1.0
      val length = math.sqrt(dashX * dashX + dashY * dashY)
      explorerX = math.max(55.0, math.min(1015.0, explorerX + (dashX / length) * 105.0))
      explorerY = math.max(115.0, math.min(655.0, explorerY + (dashY / length) * 105.0))
      energy -= 12
      dashTicks = 22
      mouseTargetActive = false
      setMessage("MYSTIC DASH!")
    } else {
      setMessage("Not enough energy for Mystic Dash. Collect relics!")
    }
    repaint()
  }

  private def useAura(): Unit = {
    if (hasWon) return
    if (energy >= 20 && shieldTicks == 0) {
      energy -= 20
      shieldTicks = 150
      setMessage("AURA SHIELD activated!")
    } else {
      setMessage("Need 20 energy to activate Aura Shield.")
    }
    repaint()
  }

  private def togglePause(): Unit = {
    if (gameTimer.isRunning) {
      gameTimer.stop()
      setMessage("Paused. Press P to continue.")
    } else if (!hasWon) {
      gameTimer.start()
      setMessage("Expedition resumed.")
    }
    repaint()
  }

  private def showExitMessage(): Unit = {
    setMessage("To leave, close this game window. Your laptop files are not changed.")
    repaint()
  }

  private def drawCrystal(g: Graphics2D, x: Int, y: Int, size: Int, color: Color): Unit = {
    val xs = Array(x, x + size / 2, x + size, x + size * 3 / 4, x + size / 2, x + size / 4)
    val ys = Array(y + size / 2, y, y + size / 2, y + size, y + size * 5 / 4, y + size)
    g.setColor(color)
    g.fillPolygon(xs, ys, xs.length)
    g.setColor(new Color(245, 250, 255, 190))
    g.drawLine(x + size / 2, y + 2, x + size / 2, y + size * 5 / 4)
  }

  private def drawWisp(g: Graphics2D, x: Int, y: Int, color: Color): Unit = {
    g.setColor(new Color(color.getRed, color.getGreen, color.getBlue, 55))
    g.fillOval(x - 22, y - 22, 44, 44)
    g.setColor(color)
    g.fillOval(x - 10, y - 10, 20, 20)
    g.setColor(new Color(255, 255, 255, 210))
    g.fillOval(x - 4, y - 5, 5, 5)
    g.fillOval(x + 3, y - 5, 5, 5)
  }

  override def paintComponent(graphics: Graphics): Unit = {
    super.paintComponent(graphics)
    val g = graphics.create().asInstanceOf[Graphics2D]
    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
    val width = getWidth
    val height = getHeight

    val topColor = if (realmIndex == 0) new Color(13, 40, 53) else if (realmIndex == 1) new Color(24, 22, 62) else new Color(29, 24, 57)
    val bottomColor = if (realmIndex == 0) new Color(13, 73, 70) else if (realmIndex == 1) new Color(52, 39, 98) else new Color(75, 38, 91)
    g.setPaint(new GradientPaint(0, 0, topColor, 0, height, bottomColor))
    g.fillRect(0, 0, width, height)

    var star = 0
    while (star < 65) {
      val sx = (star * 173 + 41) % math.max(1, width)
      val sy = (star * 97 + 25) % math.max(1, height)
      val alpha = 80 + ((star * 23) % 150)
      g.setColor(new Color(205, 225, 255, alpha))
      g.fillOval(sx, sy, 2 + (star % 3), 2 + (star % 3))
      star += 1
    }

    g.setColor(new Color(255, 255, 255, 18))
    var gridX = 35
    while (gridX < width) { g.drawLine(gridX, 95, gridX, height); gridX += 55 }
    var gridY = 120
    while (gridY < height) { g.drawLine(0, gridY, width, gridY); gridY += 55 }

    if (realmIndex == 0) {
      var tree = 0
      while (tree < 9) {
        val tx = 45 + tree * 112
        g.setColor(new Color(17, 52, 48))
        g.fillRect(tx, 150, 18, 365)
        g.setColor(new Color(27, 91, 72, 210))
        g.fillOval(tx - 33, 115 + (tree % 3) * 22, 85, 85)
        tree += 1
      }
    } else if (realmIndex == 1) {
      var book = 0
      while (book < 6) {
        val bx = 70 + book * 155
        g.setColor(new Color(115, 105, 180, 130))
        g.fillRoundRect(bx, 150 + (book % 2) * 260, 75, 90, 12, 12)
        g.setColor(new Color(220, 205, 255, 150))
        g.drawLine(bx + 12, 165 + (book % 2) * 260, bx + 63, 165 + (book % 2) * 260)
        book += 1
      }
    } else {
      var rock = 0
      while (rock < 8) {
        val rx = 35 + rock * 135
        val ry = 500 + (rock % 3) * 25
        g.setColor(new Color(71, 54, 116, 210))
        g.fillPolygon(Array(rx, rx + 34, rx + 75, rx + 52, rx + 10), Array(ry + 55, ry, ry + 32, ry + 70, ry + 75), 5)
        rock += 1
      }
    }

    g.setColor(new Color(8, 13, 30, 165))
    g.fillRoundRect(0, 0, width, 88, 0, 0)
    g.setColor(new Color(220, 235, 255))
    g.setFont(new Font("Dialog", Font.BOLD, 19))
    g.drawString("MYSTIC PORTAL EXPEDITION", 24, 31)
    g.setFont(new Font("Dialog", Font.BOLD, 14))
    g.setColor(new Color(155, 220, 245))
    g.drawString("Explorer: " + playerName + "   |   Realm " + (realmIndex + 1).toString + "/3: " + realmNames(realmIndex), 24, 58)
    g.setColor(new Color(225, 230, 250))
    g.drawString("Relics " + collectedHere.toString + "/5   Total " + totalRelics.toString, 675, 30)

    g.setColor(new Color(40, 48, 70))
    g.fillRoundRect(675, 43, 180, 15, 8, 8)
    g.setColor(new Color(88, 220, 195))
    g.fillRoundRect(675, 43, energy * 180 / 100, 15, 8, 8)
    g.setColor(Color.WHITE)
    g.setFont(new Font("Dialog", Font.PLAIN, 11))
    g.drawString("ENERGY " + energy.toString + "/100", 862, 55)

    var i = 0
    while (i < relics.length) {
      val r = relics(i)
      if (!r.collected) {
        val pulse = (math.sin(tickCount.toDouble * 0.09 + i.toDouble) * 4.0).toInt
        g.setColor(new Color(80, 220, 230, 45))
        g.fillOval(r.x - 20 - pulse, r.y - 20 - pulse, 48 + pulse * 2, 48 + pulse * 2)
        val crystalColor = if (realmIndex == 0) new Color(105, 242, 180) else if (realmIndex == 1) new Color(190, 160, 255) else new Color(120, 215, 255)
        drawCrystal(g, r.x - 10, r.y - 13 + pulse / 3, 20, crystalColor)
      }
      i += 1
    }

    val portalColor = if (collectedHere >= 5) new Color(255, 215, 110) else new Color(125, 125, 180)
    g.setColor(new Color(portalColor.getRed, portalColor.getGreen, portalColor.getBlue, 35))
    g.fillOval(portalX.toInt - 58, portalY.toInt - 72, 116, 144)
    g.setStroke(new BasicStroke(7.0f))
    g.setColor(portalColor)
    g.drawOval(portalX.toInt - 34, portalY.toInt - 52, 68, 104)
    g.setStroke(new BasicStroke(2.0f))
    g.setColor(new Color(240, 240, 255))
    g.setFont(new Font("Dialog", Font.BOLD, 12))
    g.drawString(if (collectedHere >= 5) "OPEN PORTAL" else "SEALED", portalX.toInt - 37, portalY.toInt + 75)

    drawWisp(g, wispOneX.toInt, wispOneY.toInt, new Color(180, 135, 255))
    drawWisp(g, wispTwoX.toInt, wispTwoY.toInt, new Color(105, 205, 255))

    val px = explorerX.toInt
    val py = explorerY.toInt
    if (shieldTicks > 0) {
      g.setColor(new Color(105, 235, 255, 65))
      g.fillOval(px - 28, py - 39, 56, 78)
      g.setColor(new Color(135, 245, 255, 205))
      g.setStroke(new BasicStroke(3.0f))
      g.drawOval(px - 28, py - 39, 56, 78)
      g.setStroke(new BasicStroke(1.0f))
    }
    g.setColor(new Color(8, 12, 28, 170))
    g.fillOval(px - 15, py + 18, 30, 10)
    g.setColor(new Color(55, 155, 180))
    g.fillRoundRect(px - 13, py - 9, 26, 34, 10, 10)
    g.setColor(new Color(226, 205, 170))
    g.fillOval(px - 10, py - 28, 20, 21)
    g.setColor(new Color(235, 245, 255))
    g.fillOval(px - 5, py - 21, 3, 3)
    g.fillOval(px + 3, py - 21, 3, 3)

    if (mouseTargetActive) {
      g.setColor(new Color(255, 255, 255, 130))
      g.drawOval(mouseTargetX.toInt - 9, mouseTargetY.toInt - 9, 18, 18)
    }

    g.setColor(new Color(7, 10, 25, 190))
    g.fillRoundRect(18, height - 72, width - 36, 52, 14, 14)
    g.setColor(new Color(230, 235, 255))
    g.setFont(new Font("Dialog", Font.BOLD, 13))
    g.drawString("WASD / ARROWS: MOVE   |   CLICK: WALK   |   E: COLLECT / PORTAL   |   SPACE: DASH   |   Q: AURA   |   P: PAUSE", 32, height - 49)
    g.setColor(new Color(150, 220, 230))
    g.setFont(new Font("Dialog", Font.PLAIN, 12))
    g.drawString(if (messageTicks > 0) message else realmDescriptions(realmIndex), 32, height - 29)

    if (hasWon) {
      g.setColor(new Color(5, 8, 22, 205))
      g.fillRect(0, 88, width, height - 160)
      g.setColor(new Color(245, 225, 160))
      g.setFont(new Font("Dialog", Font.BOLD, 38))
      g.drawString("MYSTIC NEXUS RESTORED!", 260, height / 2 - 10)
      g.setFont(new Font("Dialog", Font.PLAIN, 18))
      g.setColor(Color.WHITE)
      g.drawString("All three realms are free. Your expedition is complete.", 285, height / 2 + 28)
    }

    g.dispose()
  }
}

MysticPortalExpeditionEvent7.main(Array[String]())