Code Sketch


Bixuu event PhantomsLostDimensionEvent2
By: Mhalsakant School
Category: Programming
import java.awt.BasicStroke
import java.awt.BorderLayout
import java.awt.Color
import java.awt.Dimension
import java.awt.Font
import java.awt.GradientPaint
import java.awt.Graphics
import java.awt.Graphics2D
import java.awt.RenderingHints
import java.awt.event.ActionEvent
import java.awt.event.ActionListener
import java.awt.event.KeyAdapter
import java.awt.event.KeyEvent
import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent
import javax.swing.BorderFactory
import javax.swing.Box
import javax.swing.BoxLayout
import javax.swing.JButton
import javax.swing.JFrame
import javax.swing.JLabel
import javax.swing.JPanel
import javax.swing.JTextField
import javax.swing.SwingConstants
import javax.swing.SwingUtilities
import javax.swing.Timer
import javax.swing.WindowConstants
import java.util.Random

object PhantomsLostDimensionEvent2 {
  private val WINDOW_WIDTH = 960
  private val WINDOW_HEIGHT = 700
  private val FIELD_WIDTH = 920
  private val FIELD_HEIGHT = 570

  def main(args: Array[String]): Unit = {
    SwingUtilities.invokeLater(new Runnable {
      override def run(): Unit = createWindow()
    })
  }

  private def createWindow(): Unit = {
    val frame = new JFrame("INFINITY REALMS - PHANTOM'S LOST DIMENSION")
    frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE)
    frame.setSize(WINDOW_WIDTH, WINDOW_HEIGHT)
    frame.setMinimumSize(new Dimension(820, 620))
    frame.setLocationRelativeTo(null)

    val cardLayout = new java.awt.CardLayout()
    val root = new JPanel(cardLayout)
    root.setPreferredSize(new Dimension(WINDOW_WIDTH, WINDOW_HEIGHT))

    val loginPanel = new JPanel()
    loginPanel.setLayout(new BoxLayout(loginPanel, BoxLayout.Y_AXIS))
    loginPanel.setBackground(new Color(12, 10, 31))
    loginPanel.setBorder(BorderFactory.createEmptyBorder(70, 50, 55, 50))

    val title = new JLabel("PHANTOM'S LOST DIMENSION")
    title.setFont(new Font("SansSerif", Font.BOLD, 34))
    title.setForeground(new Color(221, 202, 255))
    title.setAlignmentX(0.5f)

    val season = new JLabel("INFINITY REALMS SEASON 2  |  HAUNTED REALM")
    season.setFont(new Font("SansSerif", Font.BOLD, 16))
    season.setForeground(new Color(155, 132, 220))
    season.setAlignmentX(0.5f)

    val story = new JLabel("Find the lost memories, escape the Phantom Wisps, and open the Moon Gate.")
    story.setFont(new Font("SansSerif", Font.PLAIN, 14))
    story.setForeground(new Color(220, 216, 238))
    story.setAlignmentX(0.5f)

    val nameLabel = new JLabel("ENTER YOUR EXPLORER NAME")
    nameLabel.setFont(new Font("SansSerif", Font.BOLD, 14))
    nameLabel.setForeground(new Color(190, 175, 232))
    nameLabel.setAlignmentX(0.5f)

    val nameField = new JTextField("Explorer", 20)
    nameField.setFont(new Font("SansSerif", Font.PLAIN, 18))
    nameField.setHorizontalAlignment(SwingConstants.CENTER)
    nameField.setMaximumSize(new Dimension(330, 42))
    nameField.setAlignmentX(0.5f)

    val startButton = makeButton("ENTER THE DIMENSION", new Color(103, 72, 174))
    startButton.setAlignmentX(0.5f)
    startButton.setMaximumSize(new Dimension(330, 46))

    val hint = new JLabel("Offline adventure  |  No account or internet required")
    hint.setFont(new Font("SansSerif", Font.PLAIN, 12))
    hint.setForeground(new Color(133, 125, 163))
    hint.setAlignmentX(0.5f)

    loginPanel.add(Box.createVerticalGlue())
    loginPanel.add(title)
    loginPanel.add(Box.createVerticalStrut(12))
    loginPanel.add(season)
    loginPanel.add(Box.createVerticalStrut(26))
    loginPanel.add(story)
    loginPanel.add(Box.createVerticalStrut(48))
    loginPanel.add(nameLabel)
    loginPanel.add(Box.createVerticalStrut(10))
    loginPanel.add(nameField)
    loginPanel.add(Box.createVerticalStrut(18))
    loginPanel.add(startButton)
    loginPanel.add(Box.createVerticalStrut(24))
    loginPanel.add(hint)
    loginPanel.add(Box.createVerticalGlue())

    root.add(loginPanel, "login")
    var activeGame: GamePanel = null

    val beginGame = new ActionListener {
      override def actionPerformed(e: ActionEvent): Unit = {
        val entered = nameField.getText.trim
        val playerName = if (entered.length == 0) "Explorer" else entered.take(18)
        if (activeGame != null) {
          activeGame.stopGame()
          root.remove(activeGame)
        }
        activeGame = new GamePanel(playerName, new Runnable {
          override def run(): Unit = {
            if (activeGame != null) activeGame.stopGame()
            cardLayout.show(root, "login")
            nameField.requestFocusInWindow()
          }
        })
        root.add(activeGame, "game")
        cardLayout.show(root, "game")
        activeGame.startGame()
      }
    }
    startButton.addActionListener(beginGame)
    nameField.addActionListener(beginGame)

    frame.setContentPane(root)
    frame.setVisible(true)
  }

  private def makeButton(text: String, color: Color): JButton = {
    val button = new JButton(text)
    button.setFont(new Font("SansSerif", Font.BOLD, 13))
    button.setForeground(Color.WHITE)
    button.setBackground(color)
    button.setFocusPainted(false)
    button.setBorder(BorderFactory.createEmptyBorder(10, 18, 10, 18))
    button.setOpaque(true)
    button
  }

  private class GamePanel(playerName: String, onBack: Runnable) extends JPanel(new BorderLayout()) {
    private val field = new PlayField(playerName, onBack)
    private val status = new JLabel("Collect 6 Lost Memories to unlock the Moon Gate.")
    private val pauseButton = makeButton("PAUSE", new Color(76, 65, 112))
    private val restartButton = makeButton("RESTART", new Color(80, 105, 135))
    private val backButton = makeButton("BACK TO LOGIN", new Color(112, 65, 91))

    private val bottom = new JPanel(new BorderLayout())
    private val buttonRow = new JPanel()

    private val timer = new Timer(30, new ActionListener {
      override def actionPerformed(e: ActionEvent): Unit = {
        field.updateWorld()
        status.setText(field.statusText)
        field.repaint()
      }
    })

    setBackground(new Color(13, 11, 32))
    status.setForeground(new Color(225, 218, 245))
    status.setFont(new Font("SansSerif", Font.BOLD, 13))
    status.setBorder(BorderFactory.createEmptyBorder(8, 12, 8, 12))
    status.setBackground(new Color(25, 21, 48))
    status.setOpaque(true)

    buttonRow.setBackground(new Color(20, 17, 40))
    buttonRow.add(pauseButton)
    buttonRow.add(restartButton)
    buttonRow.add(backButton)
    bottom.setBackground(new Color(20, 17, 40))
    bottom.add(status, BorderLayout.CENTER)
    bottom.add(buttonRow, BorderLayout.SOUTH)

    add(field, BorderLayout.CENTER)
    add(bottom, BorderLayout.SOUTH)

    pauseButton.addActionListener(new ActionListener {
      override def actionPerformed(e: ActionEvent): Unit = {
        field.togglePause()
        if (field.isPaused) pauseButton.setText("RESUME")
        else pauseButton.setText("PAUSE")
        field.requestFocusInWindow()
      }
    })
    restartButton.addActionListener(new ActionListener {
      override def actionPerformed(e: ActionEvent): Unit = {
        field.resetWorld()
        if (!timer.isRunning) timer.start()
        pauseButton.setText("PAUSE")
        field.requestFocusInWindow()
      }
    })
    backButton.addActionListener(new ActionListener {
      override def actionPerformed(e: ActionEvent): Unit = {
        stopGame()
        onBack.run()
      }
    })

    def startGame(): Unit = {
      timer.start()
      field.requestFocusInWindow()
    }

    def stopGame(): Unit = {
      timer.stop()
      field.stopGame()
    }
  }

  private class Shard(val x: Double, val y: Double, var found: Boolean)

  private class PlayField(playerName: String, onBack: Runnable) extends JPanel {
    private val random = new Random()
    private val fieldW = FIELD_WIDTH
    private val fieldH = FIELD_HEIGHT

    private val layouts: Array[Array[(Int, Int)]] = Array(
      Array((145, 135), (310, 110), (470, 190), (690, 135), (780, 330), (370, 420)),
      Array((125, 310), (270, 150), (450, 100), (650, 220), (790, 420), (430, 450)),
      Array((160, 160), (320, 360), (500, 130), (690, 390), (790, 170), (470, 470))
    )

    private var realm = 0
    private var playerX = 75.0
    private var playerY = 500.0
    private var facing = 1
    private var lives = 3
    private var totalMemories = 0
    private var realmMemories = 0
    private var dashFrames = 0
    private var dashCooldown = 0
    private var lanternCooldown = 0
    private var hitCooldown = 0
    private var paused = false
    private var lost = false
    private var completed = false
    private var message = "Find the glowing memories."
    private var up = false
    private var down = false
    private var left = false
    private var right = false
    private var targetX = -1.0
    private var targetY = -1.0
    private var mouseWalking = false
    private var interactRequested = false
    private var shards: Array[Shard] = makeShards()
    private var ghostX: Array[Double] = Array(760.0, 620.0, 825.0)
    private var ghostY: Array[Double] = Array(120.0, 440.0, 300.0)
    private var ghostStun: Array[Int] = Array(0, 0, 0)
    private var frameCount = 0

    setPreferredSize(new Dimension(fieldW, fieldH))
    setBackground(new Color(12, 9, 29))
    setFocusable(true)
    setDoubleBuffered(true)

    private def makeShards(): Array[Shard] = {
      layouts(realm).map(p => new Shard(p._1.toDouble, p._2.toDouble, false))
    }

    def statusText: String = {
      if (completed) "Dimension restored! You awakened the Moon Gate."
      else if (lost) "The dimension has trapped you. Press RESTART to try again."
      else "Realm " + (realm + 1) + "/3  |  Memories " + realmMemories + "/6  |  Total " + totalMemories + "  |  Hearts " + lives
    }

    def isPaused: Boolean = paused

    def togglePause(): Unit = {
      paused = !paused
      message = if (paused) "Paused - press RESUME to continue." else "Keep moving, " + playerName + "!"
      repaint()
    }

    def resetWorld(): Unit = {
      realm = 0
      playerX = 75.0
      playerY = 500.0
      lives = 3
      totalMemories = 0
      realmMemories = 0
      dashFrames = 0
      dashCooldown = 0
      lanternCooldown = 0
      hitCooldown = 0
      paused = false
      lost = false
      completed = false
      message = "Find 6 Lost Memories and reach the Moon Gate."
      up = false
      down = false
      left = false
      right = false
      mouseWalking = false
      shards = makeShards()
      resetGhosts()
      requestFocusInWindow()
      repaint()
    }

    def stopGame(): Unit = {
      paused = true
    }

    private def resetGhosts(): Unit = {
      ghostX = Array(760.0, 620.0, 825.0)
      ghostY = Array(120.0, 440.0, 300.0)
      ghostStun = Array(0, 0, 0)
    }

    addKeyListener(new KeyAdapter {
      override def keyPressed(e: KeyEvent): Unit = {
        e.getKeyCode match {
          case KeyEvent.VK_W | KeyEvent.VK_UP => up = true
          case KeyEvent.VK_S | KeyEvent.VK_DOWN => down = true
          case KeyEvent.VK_A | KeyEvent.VK_LEFT => left = true
          case KeyEvent.VK_D | KeyEvent.VK_RIGHT => right = true
          case KeyEvent.VK_SPACE =>
            if (dashCooldown <= 0 && !paused && !lost && !completed) {
              dashFrames = 12
              dashCooldown = 70
              message = "Moon Dash!"
            }
          case KeyEvent.VK_F =>
            if (lanternCooldown <= 0 && !paused && !lost && !completed) {
              var i = 0
              while (i < ghostStun.length) {
                ghostStun(i) = 90
                i += 1
              }
              lanternCooldown = 150
              message = "Lantern pulse! The Phantom Wisps are stunned."
            }
          case KeyEvent.VK_E => interactRequested = true
          case KeyEvent.VK_P => togglePause()
          case KeyEvent.VK_R => resetWorld()
          case KeyEvent.VK_ESCAPE => onBack.run()
          case _ =>
        }
      }

      override def keyReleased(e: KeyEvent): Unit = {
        e.getKeyCode match {
          case KeyEvent.VK_W | KeyEvent.VK_UP => up = false
          case KeyEvent.VK_S | KeyEvent.VK_DOWN => down = false
          case KeyEvent.VK_A | KeyEvent.VK_LEFT => left = false
          case KeyEvent.VK_D | KeyEvent.VK_RIGHT => right = false
          case _ =>
        }
      }
    })

    addMouseListener(new MouseAdapter {
      override def mousePressed(e: MouseEvent): Unit = {
        targetX = e.getX.toDouble
        targetY = e.getY.toDouble
        mouseWalking = true
        requestFocusInWindow()
      }
    })

    def updateWorld(): Unit = {
      if (paused || lost || completed) return
      frameCount += 1
      if (dashCooldown > 0) dashCooldown -= 1
      if (lanternCooldown > 0) lanternCooldown -= 1
      if (hitCooldown > 0) hitCooldown -= 1
      if (dashFrames > 0) dashFrames -= 1

      var dx = 0.0
      var dy = 0.0
      if (left) dx -= 1.0
      if (right) dx += 1.0
      if (up) dy -= 1.0
      if (down) dy += 1.0

      if (mouseWalking && dx == 0.0 && dy == 0.0) {
        val mx = targetX - playerX
        val my = targetY - playerY
        val distance = math.sqrt(mx * mx + my * my)
        if (distance < 8.0) mouseWalking = false
        else {
          dx = mx / distance
          dy = my / distance
        }
      }

      val length = math.sqrt(dx * dx + dy * dy)
      if (length > 0.0) {
        val candyBoost = math.min(totalMemories.toDouble * 0.035, 1.0)
        val baseSpeed = 3.1 + candyBoost
        val moveSpeed = if (dashFrames > 0) baseSpeed * 2.7 else baseSpeed
        playerX += (dx / length) * moveSpeed
        playerY += (dy / length) * moveSpeed
        if (dx > 0) facing = 1
        if (dx < 0) facing = -1
      }

      playerX = math.max(28.0, math.min(fieldW - 28.0, playerX))
      playerY = math.max(92.0, math.min(fieldH - 28.0, playerY))

      var s = 0
      while (s < shards.length) {
        if (!shards(s).found && distanceBetween(playerX, playerY, shards(s).x, shards(s).y) < 25.0) {
          shards(s).found = true
          realmMemories += 1
          totalMemories += 1
          message = "Lost Memory collected! Your movement is getting faster."
        }
        s += 1
      }

      var i = 0
      while (i < ghostX.length) {
        if (ghostStun(i) > 0) ghostStun(i) -= 1
        else {
          val gx = playerX - ghostX(i)
          val gy = playerY - ghostY(i)
          val distance = math.sqrt(gx * gx + gy * gy)
          if (distance > 1.0) {
            val ghostSpeed = 0.65 + realm.toDouble * 0.18 + (if (i == 0) 0.16 else 0.0)
            ghostX(i) += (gx / distance) * ghostSpeed
            ghostY(i) += (gy / distance) * ghostSpeed
          }
          if (distance < 25.0 && hitCooldown <= 0) {
            lives -= 1
            hitCooldown = 85
            playerX = 75.0
            playerY = 500.0
            message = "A Phantom Wisp caught you! You lost one heart."
            if (lives <= 0) {
              lost = true
              message = "Lost in the Dimension! Press RESTART to try again."
            }
          }
        }
        i += 1
      }

      if (interactRequested) {
        interactRequested = false
        if (realmMemories >= 6 && distanceBetween(playerX, playerY, fieldW - 90.0, 118.0) < 68.0) {
          advanceRealm()
        } else if (realmMemories < 6) {
          message = "The Moon Gate is sealed. Find all 6 Lost Memories first."
        } else {
          message = "The Moon Gate is open! Move close and press E."
        }
      }

      if (realmMemories >= 6 && distanceBetween(playerX, playerY, fieldW - 90.0, 118.0) < 48.0) {
        advanceRealm()
      }
    }

    private def distanceBetween(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 advanceRealm(): Unit = {
      if (realm < 2) {
        realm += 1
        realmMemories = 0
        playerX = 75.0
        playerY = 500.0
        shards = makeShards()
        resetGhosts()
        message = "Welcome to " + realmName + ". Find 6 more memories."
      } else {
        completed = true
        message = "You restored the Phantom Dimension! The Moon Gate is healed."
      }
    }

    private def realmName: String = {
      realm match {
        case 0 => "The Forgotten Village"
        case 1 => "The Whispering Forest"
        case _ => "The Phantom Citadel"
      }
    }

    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 w = getWidth
      val h = getHeight
      drawBackground(g, w, h)
      drawRuins(g, w, h)
      drawPortal(g, w, h)
      drawShards(g)
      drawGhosts(g)
      drawPlayer(g)
      drawHud(g, w)
      if (paused) drawOverlay(g, w, h, "PAUSED", "Press P or RESUME to continue")
      if (lost) drawOverlay(g, w, h, "LOST IN THE DIMENSION", "Press RESTART to begin again")
      if (completed) drawOverlay(g, w, h, "PHANTOM DIMENSION RESTORED!", "You awakened the Moon Gate. Congratulations, " + playerName + "!")
      g.dispose()
    }

    private def drawBackground(g: Graphics2D, w: Int, h: Int): Unit = {
      val top = realm match {
        case 0 => new Color(17, 14, 43)
        case 1 => new Color(10, 31, 42)
        case _ => new Color(34, 15, 45)
      }
      val bottom = realm match {
        case 0 => new Color(48, 25, 66)
        case 1 => new Color(18, 63, 65)
        case _ => new Color(75, 27, 62)
      }
      g.setPaint(new GradientPaint(0, 0, top, 0, h, bottom))
      g.fillRect(0, 0, w, h)

      var i = 0
      while (i < 85) {
        val sx = (i * 97 + 31) % math.max(1, w)
        val sy = (i * 53 + 17) % math.max(1, h)
        val radius = if (i % 7 == 0) 3 else 2
        g.setColor(new Color(220, 213, 255, 100 + (i % 5) * 25))
        g.fillOval(sx, sy, radius, radius)
        i += 1
      }

      g.setColor(new Color(215, 211, 244, 190))
      g.fillOval(w - 175, 45, 76, 76)
      g.setColor(new Color(top.getRed, top.getGreen, top.getBlue, 90))
      g.fillOval(w - 155, 35, 76, 76)

      g.setColor(new Color(18, 17, 38, 180))
      val hill1 = new java.awt.Polygon()
      hill1.addPoint(0, h - 145)
      hill1.addPoint(w / 4, h - 230)
      hill1.addPoint(w / 2, h - 150)
      hill1.addPoint(w * 3 / 4, h - 235)
      hill1.addPoint(w, h - 145)
      hill1.addPoint(w, h)
      hill1.addPoint(0, h)
      g.fillPolygon(hill1)

      g.setColor(new Color(14, 13, 31, 220))
      g.fillRect(0, h - 58, w, 58)
    }

    private def drawRuins(g: Graphics2D, w: Int, h: Int): Unit = {
      var i = 0
      while (i < 6) {
        val x = 45 + i * 155
        val y = h - 112 - (i % 2) * 12
        g.setColor(new Color(39, 35, 62))
        g.fillRoundRect(x, y, 42, 75, 12, 12)
        g.setColor(new Color(93, 76, 118))
        g.drawRoundRect(x, y, 42, 75, 12, 12)
        g.setColor(new Color(148, 130, 178, 150))
        g.drawArc(x + 10, y + 12, 22, 27, 0, 180)
        i += 1
      }
      g.setColor(new Color(22, 28, 40, 210))
      g.fillRect(0, h - 90, w, 32)
    }

    private def drawPortal(g: Graphics2D, w: Int, h: Int): Unit = {
      val x = w - 90
      val y = 118
      val open = realmMemories >= 6
      val glow = if (open) new Color(109, 244, 215, 85) else new Color(119, 91, 160, 70)
      g.setColor(glow)
      g.fillOval(x - 47, y - 48, 94, 96)
      g.setColor(if (open) new Color(133, 255, 221) else new Color(130, 112, 162))
      g.setStroke(new BasicStroke(5.0f))
      g.drawOval(x - 37, y - 40, 74, 82)
      g.setStroke(new BasicStroke(2.0f))
      g.drawOval(x - 26, y - 29, 52, 60)
      g.setColor(new Color(14, 9, 31, 225))
      g.fillOval(x - 19, y - 24, 38, 52)
      g.setColor(if (open) Color.WHITE else new Color(173, 158, 197))
      g.setFont(new Font("SansSerif", Font.BOLD, 11))
      g.drawString(if (open) "MOON GATE" else "SEALED", x - 31, y + 58)
    }

    private def drawShards(g: Graphics2D): Unit = {
      var i = 0
      while (i < shards.length) {
        if (!shards(i).found) {
          val x = shards(i).x.toInt
          val y = shards(i).y.toInt
          val bob = (math.sin((frameCount + i * 13).toDouble * 0.08) * 5.0).toInt
          g.setColor(new Color(170, 115, 255, 70))
          g.fillOval(x - 17, y - 17 + bob, 34, 34)
          val crystal = new java.awt.Polygon()
          crystal.addPoint(x, y - 15 + bob)
          crystal.addPoint(x + 10, y + bob)
          crystal.addPoint(x, y + 15 + bob)
          crystal.addPoint(x - 10, y + bob)
          g.setColor(new Color(182, 143, 255))
          g.fillPolygon(crystal)
          g.setColor(Color.WHITE)
          g.drawLine(x, y - 11 + bob, x, y + 10 + bob)
        }
        i += 1
      }
    }

    private def drawGhosts(g: Graphics2D): Unit = {
      var i = 0
      while (i < ghostX.length) {
        val x = ghostX(i).toInt
        val y = ghostY(i).toInt
        val bob = (math.sin((frameCount + i * 20).toDouble * 0.06) * 5.0).toInt
        val stunned = ghostStun(i) > 0
        val bodyColor = if (stunned) new Color(119, 236, 255, 220) else new Color(205, 186, 244, 225)
        g.setColor(new Color(bodyColor.getRed, bodyColor.getGreen, bodyColor.getBlue, 55))
        g.fillOval(x - 25, y - 25 + bob, 50, 50)
        g.setColor(bodyColor)
        g.fillOval(x - 16, y - 19 + bob, 32, 34)
        val tail = new java.awt.Polygon()
        tail.addPoint(x - 15, y + 3 + bob)
        tail.addPoint(x - 8, y + 19 + bob)
        tail.addPoint(x, y + 10 + bob)
        tail.addPoint(x + 8, y + 19 + bob)
        tail.addPoint(x + 16, y + 3 + bob)
        g.fillPolygon(tail)
        g.setColor(new Color(53, 40, 84))
        g.fillOval(x - 8, y - 5 + bob, 5, 7)
        g.fillOval(x + 3, y - 5 + bob, 5, 7)
        i += 1
      }
    }

    private def drawPlayer(g: Graphics2D): Unit = {
      val x = playerX.toInt
      val y = playerY.toInt
      if (hitCooldown <= 0 || (hitCooldown / 5) % 2 == 0) {
        g.setColor(new Color(80, 210, 255, 75))
        g.fillOval(x - 22, y - 22, 44, 44)
      }
      g.setColor(new Color(38, 105, 154))
      g.fillOval(x - 12, y - 17, 24, 24)
      g.setColor(new Color(45, 55, 96))
      val cloak = new java.awt.Polygon()
      cloak.addPoint(x - 13, y - 4)
      cloak.addPoint(x + 13, y - 4)
      cloak.addPoint(x + 18, y + 18)
      cloak.addPoint(x - 18, y + 18)
      g.fillPolygon(cloak)
      g.setColor(new Color(223, 240, 255))
      g.fillOval(x - 7, y - 12, 4, 5)
      g.fillOval(x + 3, y - 12, 4, 5)
      g.setColor(new Color(135, 239, 255))
      g.fillOval(x + facing * 10 - 4, y + 1, 9, 9)
      if (dashFrames > 0) {
        g.setColor(new Color(119, 228, 255, 120))
        g.drawOval(x - 27, y - 27, 54, 54)
      }
    }

    private def drawHud(g: Graphics2D, w: Int): Unit = {
      g.setColor(new Color(8, 7, 22, 195))
      g.fillRoundRect(12, 10, w - 24, 62, 18, 18)
      g.setColor(new Color(232, 222, 255))
      g.setFont(new Font("SansSerif", Font.BOLD, 17))
      g.drawString("PHANTOM'S LOST DIMENSION", 28, 34)
      g.setFont(new Font("SansSerif", Font.PLAIN, 12))
      g.setColor(new Color(190, 178, 222))
      g.drawString("Explorer: " + playerName + "   |   " + realmName, 28, 55)
      g.setColor(new Color(255, 221, 151))
      g.drawString("MEMORIES " + realmMemories + "/6", w - 245, 34)
      g.setColor(new Color(255, 153, 186))
      g.drawString("HEARTS " + lives, w - 245, 55)
      g.setColor(new Color(202, 191, 230))
      g.drawString(message, 28, 91)
    }

    private def drawOverlay(g: Graphics2D, w: Int, h: Int, heading: String, subheading: String): Unit = {
      g.setColor(new Color(5, 4, 17, 190))
      g.fillRect(0, 0, w, h)
      g.setColor(new Color(228, 212, 255))
      g.setFont(new Font("SansSerif", Font.BOLD, 29))
      val fm = g.getFontMetrics
      g.drawString(heading, (w - fm.stringWidth(heading)) / 2, h / 2 - 12)
      g.setFont(new Font("SansSerif", Font.PLAIN, 15))
      val fm2 = g.getFontMetrics
      g.setColor(new Color(211, 199, 235))
      g.drawString(subheading, (w - fm2.stringWidth(subheading)) / 2, h / 2 + 23)
    }
  }
}

PhantomsLostDimensionEvent2.main(Array[String]())