Code Sketch


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

object NeonFutureUprisingEvent4 {
  def main(args: Array[String]): Unit = {
    SwingUtilities.invokeLater(new Runnable {
      def run(): Unit = {
        val app = new NeonFutureAppFrame()
        app.setVisible(true)
      }
    })
  }
}

class NeonFutureAppFrame extends JFrame("SPRING SEASON EVENT 4 - NEON FUTURE UPRISING") {
  private val layoutCards = new CardLayout()
  private val rootPanel = new JPanel(layoutCards)
  private val gamePanel = new NeonCityGamePanel(new Runnable {
    def run(): Unit = showMenu()
  })
  private var playerName = "PLAYER"

  private val titleColor = new Color(92, 255, 238)
  private val dark = new Color(8, 12, 35)
  private val buttonColor = new Color(23, 43, 80)

  private val loginPanel = new JPanel(new BorderLayout(12, 12))
  private val nameField = new JTextField(18)
  private val loginStatus = new JLabel("ENTER YOUR CALLSIGN TO CONNECT", SwingConstants.CENTER)

  private val menuPanel = new JPanel(new BorderLayout(12, 12))
  private val menuWelcome = new JLabel("WELCOME, PLAYER", SwingConstants.CENTER)

  initLoginPanel()
  initMenuPanel()

  rootPanel.add(loginPanel, "LOGIN")
  rootPanel.add(menuPanel, "MENU")
  rootPanel.add(gamePanel, "GAME")

  setContentPane(rootPanel)
  setSize(1000, 700)
  setMinimumSize(new Dimension(850, 620))
  setLocationRelativeTo(null)
  setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE)
  addWindowListener(new WindowAdapter {
    override def windowClosing(e: WindowEvent): Unit = gamePanel.stopGame()
  })
  layoutCards.show(rootPanel, "LOGIN")

  private def styleButton(button: JButton): Unit = {
    button.setForeground(Color.WHITE)
    button.setBackground(buttonColor)
    button.setFocusPainted(false)
    button.setFont(new Font("SansSerif", Font.BOLD, 16))
    button.setBorder(BorderFactory.createCompoundBorder(
      BorderFactory.createLineBorder(titleColor, 1),
      BorderFactory.createEmptyBorder(12, 20, 12, 20)
    ))
  }

  private def initLoginPanel(): Unit = {
    loginPanel.setBackground(dark)
    val heading = new JLabel("NEON FUTURE UPRISING", SwingConstants.CENTER)
    heading.setForeground(titleColor)
    heading.setFont(new Font("SansSerif", Font.BOLD, 34))
    val sub = new JLabel("A FUTURISTIC CITY ADVENTURE", SwingConstants.CENTER)
    sub.setForeground(Color.WHITE)
    sub.setFont(new Font("SansSerif", Font.PLAIN, 16))

    val center = new JPanel()
    center.setOpaque(false)
    center.setLayout(new java.awt.GridBagLayout())
    val c = new java.awt.GridBagConstraints()
    c.gridx = 0
    c.gridy = 0
    c.insets = new java.awt.Insets(8, 8, 8, 8)
    val prompt = new JLabel("PLAYER CALLSIGN")
    prompt.setForeground(new Color(190, 220, 255))
    prompt.setFont(new Font("SansSerif", Font.BOLD, 15))
    center.add(prompt, c)
    c.gridy = 1
    nameField.setFont(new Font("SansSerif", Font.PLAIN, 19))
    nameField.setHorizontalAlignment(SwingConstants.CENTER)
    nameField.setBackground(new Color(18, 28, 58))
    nameField.setForeground(Color.WHITE)
    nameField.setCaretColor(Color.WHITE)
    nameField.setBorder(BorderFactory.createLineBorder(titleColor, 2))
    center.add(nameField, c)
    c.gridy = 2
    loginStatus.setForeground(new Color(255, 210, 110))
    center.add(loginStatus, c)
    c.gridy = 3
    val loginButton = new JButton("CONNECT TO NEON CITY")
    styleButton(loginButton)
    loginButton.addActionListener(new ActionListener {
      def actionPerformed(e: ActionEvent): Unit = {
        val entered = nameField.getText.trim
        if (entered.length == 0) {
          loginStatus.setText("PLEASE ENTER A CALLSIGN FIRST")
        } else {
          playerName = entered.take(18)
          menuWelcome.setText("WELCOME, " + playerName.toUpperCase)
          layoutCards.show(rootPanel, "MENU")
        }
      }
    })
    center.add(loginButton, c)

    val top = new JPanel(new BorderLayout())
    top.setOpaque(false)
    top.add(heading, BorderLayout.CENTER)
    top.add(sub, BorderLayout.SOUTH)
    top.setBorder(BorderFactory.createEmptyBorder(75, 20, 10, 20))
    loginPanel.add(top, BorderLayout.NORTH)
    loginPanel.add(center, BorderLayout.CENTER)
    val footer = new JLabel("EVENT 04  |  FUTURISTIC WORLD  |  OFFLINE ARCADE ADVENTURE", SwingConstants.CENTER)
    footer.setForeground(new Color(130, 160, 205))
    footer.setBorder(BorderFactory.createEmptyBorder(12, 10, 25, 10))
    loginPanel.add(footer, BorderLayout.SOUTH)
  }

  private def initMenuPanel(): Unit = {
    menuPanel.setBackground(dark)
    val heading = new JLabel("NEON FUTURE UPRISING", SwingConstants.CENTER)
    heading.setForeground(titleColor)
    heading.setFont(new Font("SansSerif", Font.BOLD, 32))
    menuWelcome.setForeground(Color.WHITE)
    menuWelcome.setFont(new Font("SansSerif", Font.BOLD, 18))

    val top = new JPanel(new BorderLayout(5, 8))
    top.setOpaque(false)
    top.add(heading, BorderLayout.CENTER)
    top.add(menuWelcome, BorderLayout.SOUTH)
    top.setBorder(BorderFactory.createEmptyBorder(55, 20, 20, 20))

    val center = new JPanel(new java.awt.GridLayout(3, 1, 12, 12))
    center.setOpaque(false)
    center.setBorder(BorderFactory.createEmptyBorder(20, 250, 30, 250))
    val play = new JButton("ENTER NEON CITY")
    val how = new JButton("HOW TO PLAY")
    val back = new JButton("BACK TO LOGIN")
    styleButton(play)
    styleButton(how)
    styleButton(back)
    play.addActionListener(new ActionListener {
      def actionPerformed(e: ActionEvent): Unit = {
        gamePanel.setPlayerName(playerName)
        gamePanel.resetGame()
        layoutCards.show(rootPanel, "GAME")
        gamePanel.startGame()
        SwingUtilities.invokeLater(new Runnable { def run(): Unit = gamePanel.requestFocusInWindow() })
      }
    })
    how.addActionListener(new ActionListener {
      def actionPerformed(e: ActionEvent): Unit = {
        javax.swing.JOptionPane.showMessageDialog(NeonFutureAppFrame.this,
          "WASD / ARROWS = MOVE\nSPACE = HOVER DASH\nE = RESCUE / DELIVER CITIZEN\nF = PULSE TAG (STUN DRONES)\nCOLLECT NEON CORES, RESCUE CITIZENS, RETURN TO BASE, THEN ACTIVATE THE EXIT GATE.",
          "HOW TO PLAY", javax.swing.JOptionPane.INFORMATION_MESSAGE)
      }
    })
    back.addActionListener(new ActionListener {
      def actionPerformed(e: ActionEvent): Unit = layoutCards.show(rootPanel, "LOGIN")
    })
    center.add(play)
    center.add(how)
    center.add(back)
    menuPanel.add(top, BorderLayout.NORTH)
    menuPanel.add(center, BorderLayout.CENTER)
    val footer = new JLabel("RESCUE THE CITY. RESTORE THE NEON CORE.", SwingConstants.CENTER)
    footer.setForeground(new Color(130, 160, 205))
    footer.setBorder(BorderFactory.createEmptyBorder(10, 10, 28, 10))
    menuPanel.add(footer, BorderLayout.SOUTH)
  }

  private def showMenu(): Unit = {
    gamePanel.stopGame()
    layoutCards.show(rootPanel, "MENU")
  }
}

case class NeonCore(var x: Double, var y: Double, var collected: Boolean)
case class CityCitizen(var x: Double, var y: Double, var status: Int, val id: Int)
case class RogueDrone(var x: Double, var y: Double, var stunned: Int, var phase: Double)

class NeonCityGamePanel(backAction: Runnable) extends JPanel with ActionListener with KeyListener {
  private val rng = new Random()
  private val timer = new Timer(16, this)
  private val heldKeys = scala.collection.mutable.Set[Int]()
  private val cores = ArrayBuffer[NeonCore]()
  private val citizens = ArrayBuffer[CityCitizen]()
  private val drones = ArrayBuffer[RogueDrone]()
  private var userName = "PLAYER"
  private var playerX = 100.0
  private var playerY = 520.0
  private var playerHealth = 100
  private var energy = 100
  private var credits = 0
  private var rescuedTotal = 0
  private var level = 1
  private var tickCount = 0
  private var dashTicks = 0
  private var dashCooldown = 0
  private var pulseFlash = 0
  private var damageCooldown = 0
  private var gamePaused = false
  private var finished = false
  private var carrying = 0
  private var message = "COLLECT NEON CORES AND RESCUE CITY CITIZENS"
  private val baseX = 92.0
  private val baseY = 530.0
  private val gateX = 900.0
  private val gateY = 92.0
  private var worldName = "NEON DOWNTOWN"

  setPreferredSize(new Dimension(960, 620))
  setBackground(new Color(7, 10, 28))
  setFocusable(true)
  addKeyListener(this)

  def setPlayerName(value: String): Unit = { userName = value }
  def startGame(): Unit = { if (!timer.isRunning) timer.start(); requestFocusInWindow() }
  def stopGame(): Unit = { if (timer.isRunning) timer.stop() }

  def resetGame(): Unit = {
    playerX = baseX
    playerY = baseY
    playerHealth = 100
    energy = 100
    credits = 0
    rescuedTotal = 0
    level = 1
    tickCount = 0
    dashTicks = 0
    dashCooldown = 0
    pulseFlash = 0
    damageCooldown = 0
    gamePaused = false
    finished = false
    carrying = 0
    heldKeys.clear()
    setupLevel()
    message = "WELCOME TO NEON CITY, " + userName.toUpperCase
    repaint()
  }

  private def setupLevel(): Unit = {
    cores.clear()
    citizens.clear()
    drones.clear()
    worldName = level match {
      case 1 => "NEON DOWNTOWN"
      case 2 => "SKYBRIDGE DISTRICT"
      case 3 => "HOLOGRAM GARDENS"
      case 4 => "REACTOR QUARTER"
      case _ => "THE NEON CORE"
    }
    var i = 0
    while (i < 4 + level) {
      val x = 180 + rng.nextInt(690)
      val y = 125 + rng.nextInt(410)
      cores += NeonCore(x.toDouble, y.toDouble, false)
      i += 1
    }
    i = 0
    while (i < 2 + (level / 2)) {
      val x = 240 + rng.nextInt(600)
      val y = 150 + rng.nextInt(350)
      citizens += CityCitizen(x.toDouble, y.toDouble, 0, i)
      i += 1
    }
    i = 0
    while (i < 1 + level) {
      val x = 260 + rng.nextInt(600)
      val y = 150 + rng.nextInt(360)
      drones += RogueDrone(x.toDouble, y.toDouble, 0, rng.nextDouble() * 6.28)
      i += 1
    }
    playerX = baseX
    playerY = baseY
    carrying = 0
    playerHealth = 100
    energy = 100
    message = "DISTRICT " + level + " : COLLECT " + cores.size + " CORES AND RESCUE " + citizens.size + " CITIZENS"
  }

  private def distance(ax: Double, ay: Double, bx: Double, by: Double): Double = {
    val dx = ax - bx
    val dy = ay - by
    math.sqrt(dx * dx + dy * dy)
  }

  private def collectedCoreCount: Int = cores.count(_.collected)
  private def savedCitizenCount: Int = citizens.count(_.status == 2)
  private def requiredCores: Int = cores.size
  private def requiredCitizens: Int = citizens.size

  private def tryInteract(): Unit = {
    if (finished || gamePaused) return
    if (distance(playerX, playerY, baseX, baseY) < 76 && carrying > 0) {
      val delivered = carrying
      carrying = 0
      rescuedTotal += delivered
      credits += delivered * 50
      var n = 0
      while (n < citizens.length) {
        if (citizens(n).status == 1) citizens(n).status = 2
        n += 1
      }
      message = "CITIZENS DELIVERED! +" + (delivered * 50) + " CREDITS"
      return
    }
    var nearest: CityCitizen = null
    var nearestDistance = 55.0
    var i = 0
    while (i < citizens.length) {
      val c = citizens(i)
      val d = distance(playerX, playerY, c.x, c.y)
      if (c.status == 0 && d < nearestDistance) { nearest = c; nearestDistance = d }
      i += 1
    }
    if (nearest != null) {
      nearest.status = 1
      carrying += 1
      message = "CITIZEN RESCUED - RETURN TO YOUR BASE"
      return
    }
    if (distance(playerX, playerY, gateX, gateY) < 72) {
      if (collectedCoreCount >= requiredCores && savedCitizenCount >= requiredCitizens) {
        if (level >= 5) {
          finished = true
          message = "NEON CORE RESTORED! YOU SAVED THE CITY!"
        } else {
          level += 1
          setupLevel()
        }
      } else {
        message = "GATE LOCKED: COLLECT ALL CORES AND DELIVER ALL CITIZENS"
      }
    }
  }

  private def pulseTag(): Unit = {
    if (energy < 18 || gamePaused || finished) { message = "NOT ENOUGH ENERGY FOR PULSE TAG"; return }
    energy -= 18
    pulseFlash = 18
    var stunned = 0
    var i = 0
    while (i < drones.length) {
      if (distance(playerX, playerY, drones(i).x, drones(i).y) < 155) {
        drones(i).stunned = 150
        stunned += 1
      }
      i += 1
    }
    message = if (stunned > 0) "PULSE TAG! " + stunned + " DRONE(S) PAUSED" else "PULSE TAG SENT - NO DRONES IN RANGE"
  }

  private def dash(): Unit = {
    if (dashCooldown == 0 && energy >= 10 && !gamePaused && !finished) {
      dashTicks = 9
      dashCooldown = 55
      energy -= 10
    }
  }

  def actionPerformed(e: ActionEvent): Unit = {
    if (!gamePaused && !finished) updateWorld()
    repaint()
  }

  private def updateWorld(): Unit = {
    tickCount += 1
    if (dashCooldown > 0) dashCooldown -= 1
    if (dashTicks > 0) dashTicks -= 1
    if (pulseFlash > 0) pulseFlash -= 1
    if (damageCooldown > 0) damageCooldown -= 1
    if (energy < 100 && tickCount % 8 == 0) energy += 1

    var moveSpeed = 2.65 + math.min(1.8, collectedCoreCount * 0.18)
    if (dashTicks > 0) moveSpeed *= 2.8
    if (heldKeys.contains(KeyEvent.VK_W) || heldKeys.contains(KeyEvent.VK_UP)) playerY -= moveSpeed
    if (heldKeys.contains(KeyEvent.VK_S) || heldKeys.contains(KeyEvent.VK_DOWN)) playerY += moveSpeed
    if (heldKeys.contains(KeyEvent.VK_A) || heldKeys.contains(KeyEvent.VK_LEFT)) playerX -= moveSpeed
    if (heldKeys.contains(KeyEvent.VK_D) || heldKeys.contains(KeyEvent.VK_RIGHT)) playerX += moveSpeed
    playerX = math.max(35.0, math.min(925.0, playerX))
    playerY = math.max(90.0, math.min(580.0, playerY))

    var i = 0
    while (i < cores.length) {
      val core = cores(i)
      if (!core.collected && distance(playerX, playerY, core.x, core.y) < 25) {
        core.collected = true
        credits += 20
        energy = math.min(100, energy + 12)
        message = "NEON CORE COLLECTED! +20 CREDITS"
      }
      i += 1
    }

    i = 0
    while (i < citizens.length) {
      val c = citizens(i)
      if (c.status == 1) {
        c.x = playerX - 23.0 - (i % 3) * 13.0
        c.y = playerY + 20.0 + (i % 2) * 12.0
      }
      i += 1
    }

    i = 0
    while (i < drones.length) {
      val d = drones(i)
      if (d.stunned > 0) d.stunned -= 1
      else {
        val dx = playerX - d.x
        val dy = playerY - d.y
        val len = math.max(1.0, math.sqrt(dx * dx + dy * dy))
        val droneSpeed = 0.62 + level * 0.12
        d.x += dx / len * droneSpeed
        d.y += dy / len * droneSpeed
      }
      d.phase += 0.08
      if (d.stunned == 0 && distance(playerX, playerY, d.x, d.y) < 26 && damageCooldown == 0) {
        playerHealth -= 8
        damageCooldown = 45
        message = "DRONE TAGGED YOU! USE F TO PULSE TAG"
        if (playerHealth <= 0) {
          playerHealth = 100
          playerX = baseX
          playerY = baseY
          carrying = 0
          for (citizen <- citizens if citizen.status == 1) citizen.status = 0
          message = "REBOOTED AT BASE - YOUR CARRIED CITIZENS WERE LOST"
        }
      }
      i += 1
    }
  }

  def keyTyped(e: KeyEvent): Unit = {}
  def keyPressed(e: KeyEvent): Unit = {
    val code = e.getKeyCode
    heldKeys += code
    if (code == KeyEvent.VK_SPACE) dash()
    if (code == KeyEvent.VK_E) tryInteract()
    if (code == KeyEvent.VK_F) pulseTag()
    if (code == KeyEvent.VK_P) gamePaused = !gamePaused
    if (code == KeyEvent.VK_B) backAction.run()
    if (code == KeyEvent.VK_R && finished) resetGame()
  }
  def keyReleased(e: KeyEvent): Unit = { heldKeys -= e.getKeyCode }

  override def paintComponent(g: Graphics): Unit = {
    super.paintComponent(g)
    val g2 = g.create().asInstanceOf[Graphics2D]
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
    drawWorld(g2)
    g2.dispose()
  }

  private def drawWorld(g: Graphics2D): Unit = {
    val w = getWidth
    val h = getHeight
    g.setPaint(new GradientPaint(0, 0, new Color(7, 10, 33), 0, h, new Color(18, 28, 66)))
    g.fillRect(0, 0, w, h)

    var b = 0
    while (b < 15) {
      val bx = b * 72 - 8
      val bh = 90 + (b * 37 % 135)
      g.setColor(new Color(13, 24, 56))
      g.fillRoundRect(bx, 100 + (220 - bh), 58, bh + 220, 8, 8)
      g.setColor(new Color(32, 80, 115, 150))
      var wy = 130
      while (wy < 530) {
        var wx = bx + 10
        while (wx < bx + 52) {
          if ((wx + wy + b) % 3 != 0) g.fillRect(wx, wy, 4, 7)
          wx += 15
        }
        wy += 25
      }
      b += 1
    }

    g.setColor(new Color(16, 33, 62))
    g.fillRect(0, 560, w, 60)
    g.setColor(new Color(34, 190, 205, 90))
    var gridX = 0
    while (gridX < w) { g.drawLine(gridX, 560, gridX - 120, h); gridX += 48 }
    var gridY = 570
    while (gridY < h) { g.drawLine(0, gridY, w, gridY); gridY += 16 }

    // Safe base and exit gate
    g.setColor(new Color(20, 220, 190, 55))
    g.fillOval((baseX - 43).toInt, (baseY - 43).toInt, 86, 86)
    g.setColor(new Color(80, 255, 224))
    g.setStroke(new BasicStroke(3f))
    g.drawOval((baseX - 31).toInt, (baseY - 31).toInt, 62, 62)
    g.setFont(new Font("SansSerif", Font.BOLD, 11))
    g.drawString("RESCUE BASE", (baseX - 39).toInt, (baseY + 53).toInt)

    val gateColor = if (collectedCoreCount >= requiredCores && savedCitizenCount >= requiredCitizens) new Color(255, 220, 90) else new Color(120, 110, 210)
    g.setColor(new Color(gateColor.getRed, gateColor.getGreen, gateColor.getBlue, 55))
    g.fillOval((gateX - 42).toInt, (gateY - 42).toInt, 84, 84)
    g.setColor(gateColor)
    g.setStroke(new BasicStroke(4f))
    g.drawOval((gateX - 29).toInt, (gateY - 29).toInt, 58, 58)
    g.drawArc((gateX - 20).toInt, (gateY - 20).toInt, 40, 40, 0, 270)
    g.drawString("EXIT GATE", (gateX - 32).toInt, (gateY + 54).toInt)

    for (core <- cores if !core.collected) {
      val pulse = (math.sin(tickCount * 0.09 + core.x) * 3).toInt
      g.setColor(new Color(80, 255, 240, 70))
      g.fillOval((core.x - 15 - pulse).toInt, (core.y - 15 - pulse).toInt, 30 + pulse * 2, 30 + pulse * 2)
      g.setColor(new Color(90, 255, 245))
      val x = core.x.toInt
      val y = core.y.toInt
      val poly = new java.awt.Polygon(Array(x, x + 9, x + 4, x - 6, x - 10), Array(y - 12, y - 2, y + 12, y + 8, y - 4), 5)
      g.fillPolygon(poly)
    }

    for (citizen <- citizens if citizen.status != 2) {
      g.setColor(if (citizen.status == 1) new Color(255, 218, 110) else new Color(120, 210, 255))
      g.fillOval((citizen.x - 8).toInt, (citizen.y - 15).toInt, 16, 16)
      g.fillRoundRect((citizen.x - 7).toInt, (citizen.y).toInt, 14, 19, 8, 8)
      if (citizen.status == 0) {
        g.setColor(Color.WHITE)
        g.drawString("!", (citizen.x - 3).toInt, (citizen.y - 21).toInt)
      }
    }

    for (drone <- drones) {
      val dColor = if (drone.stunned > 0) new Color(120, 255, 255) else new Color(255, 90, 160)
      g.setColor(new Color(dColor.getRed, dColor.getGreen, dColor.getBlue, 55))
      g.fillOval((drone.x - 20).toInt, (drone.y - 20).toInt, 40, 40)
      g.setColor(dColor)
      g.fillOval((drone.x - 9).toInt, (drone.y - 9).toInt, 18, 18)
      g.setColor(new Color(8, 12, 35))
      g.fillOval((drone.x - 3).toInt, (drone.y - 3).toInt, 6, 6)
      if (drone.stunned > 0) {
        g.setColor(Color.WHITE)
        g.drawString("Z", (drone.x + 10).toInt, (drone.y - 10).toInt)
      }
    }

    // Player avatar
    val playerGlow = if (dashTicks > 0) new Color(255, 255, 150, 100) else new Color(50, 255, 240, 65)
    g.setColor(playerGlow)
    g.fillOval((playerX - 26).toInt, (playerY - 26).toInt, 52, 52)
    g.setColor(new Color(90, 255, 230))
    g.fillRoundRect((playerX - 11).toInt, (playerY - 15).toInt, 22, 30, 10, 10)
    g.setColor(new Color(235, 255, 255))
    g.fillOval((playerX - 7).toInt, (playerY - 22).toInt, 14, 14)
    g.setColor(new Color(9, 30, 55))
    g.drawString(userName.take(12), (playerX - 28).toInt, (playerY - 30).toInt)
    if (pulseFlash > 0) {
      g.setColor(new Color(80, 245, 255, 100))
      g.setStroke(new BasicStroke(4f))
      val radius = (18 - pulseFlash) * 8 + 20
      g.drawOval((playerX - radius).toInt, (playerY - radius).toInt, radius * 2, radius * 2)
    }

    // HUD
    g.setColor(new Color(5, 10, 28, 225))
    g.fillRoundRect(12, 12, w - 24, 68, 18, 18)
    g.setColor(new Color(82, 245, 230))
    g.setFont(new Font("SansSerif", Font.BOLD, 17))
    g.drawString("NEON FUTURE UPRISING", 28, 38)
    g.setFont(new Font("SansSerif", Font.PLAIN, 13))
    g.setColor(Color.WHITE)
    g.drawString("DISTRICT " + level + "/5  -  " + worldName, 29, 61)
    g.drawString("CORES " + collectedCoreCount + "/" + requiredCores, 310, 36)
    g.drawString("SAVED " + savedCitizenCount + "/" + requiredCitizens + "  CARRYING " + carrying, 310, 59)
    g.drawString("CREDITS " + credits, 540, 36)
    g.drawString("HP " + playerHealth + "   ENERGY " + energy, 540, 59)
    g.setColor(new Color(80, 255, 220))
    g.fillRoundRect(750, 27, 165, 12, 8, 8)
    g.setColor(new Color(255, 110, 150))
    g.fillRoundRect(750, 48, 165, 8, 8, 8)
    g.setColor(Color.WHITE)
    g.drawString("E: INTERACT   F: PULSE   SPACE: DASH   B: MENU", 20, h - 14)

    g.setColor(new Color(6, 10, 25, 210))
    g.fillRoundRect(220, h - 53, 520, 30, 12, 12)
    g.setColor(new Color(255, 230, 130))
    g.setFont(new Font("SansSerif", Font.BOLD, 12))
    g.drawString(message, 235, h - 33)

    if (gamePaused || finished) {
      g.setColor(new Color(4, 7, 20, 195))
      g.fillRect(0, 0, w, h)
      g.setFont(new Font("SansSerif", Font.BOLD, 34))
      g.setColor(if (finished) new Color(100, 255, 205) else Color.WHITE)
      val text = if (finished) "NEON CITY RESTORED!" else "GAME PAUSED"
      val metrics = g.getFontMetrics
      g.drawString(text, (w - metrics.stringWidth(text)) / 2, h / 2 - 12)
      g.setFont(new Font("SansSerif", Font.PLAIN, 16))
      g.setColor(Color.WHITE)
      val sub = if (finished) "PRESS R TO PLAY AGAIN  |  PRESS B FOR MENU" else "PRESS P TO RESUME  |  PRESS B FOR MENU"
      g.drawString(sub, (w - g.getFontMetrics.stringWidth(sub)) / 2, h / 2 + 28)
    }
  }
}

NeonFutureUprisingEvent4.main(Array[String]())