Code Sketch


bixuu
By: Mhalsakant School
Category: Programming
import java.awt.{AlphaComposite, BasicStroke, Color, Cursor, Dimension, Font, Graphics, Graphics2D, GradientPaint, Polygon, RenderingHints}
import java.awt.event.{ActionEvent, ActionListener, KeyAdapter, KeyEvent, MouseAdapter, MouseEvent}
import java.awt.geom.{Ellipse2D, RoundRectangle2D}
import java.util.Random
import javax.swing.{JFrame, JPanel, SwingUtilities, Timer, WindowConstants}
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer

// ================================================================
// SPRING SEASON: CYBER BLOOM - GLITCH IN THE GARDEN
// Original, self-contained Scala + Java Swing animated mini-game.
// No external images, libraries, game engine or network are required.
// Controls: WASD / arrows = move, E = interact, SPACE = dash,
//           F = glow mode, M = mini-map, ESC = pause, R = restart.
// ================================================================

object SpringSeasonCyberBloomGlitch {
  val APP_TITLE = "SPRING SEASON: CYBER BLOOM - GLITCH IN THE GARDEN"
  val WORLD_W = 1900
  val WORLD_H = 1320
  val START_W = 1180
  val START_H = 760
  val GOAL_COUNT = 6

  final class Bloom(val x: Double, val y: Double, val hue: Int, val label: String) {
    var collected = false
  }
  final class GardenFlower(val x: Double, val y: Double, val size: Double, val hue: Int, val phase: Double, val glitch: Boolean)
  final class GardenTree(val x: Double, val y: Double, val size: Double, val hue: Int)
  final class Particle(var x: Double, var y: Double, var vx: Double, var vy: Double, val size: Double, val hue: Int, var life: Double)

  val keys = mutable.Set[Int]()
  val blooms = ArrayBuffer[Bloom]()
  val gardenFlowers = ArrayBuffer[GardenFlower]()
  val trees = ArrayBuffer[GardenTree]()
  val particles = ArrayBuffer[Particle]()
  val random = new Random(2782013L)

  val BG_TOP = new Color(7, 13, 31)
  val BG_BOTTOM = new Color(18, 57, 62)
  val DEEP = new Color(13, 27, 43)
  val CYAN = new Color(70, 244, 231)
  val MINT = new Color(139, 255, 187)
  val PINK = new Color(255, 91, 194)
  val PURPLE = new Color(162, 103, 255)
  val GOLD = new Color(255, 222, 123)
  val WHITE = new Color(238, 250, 255)
  val MUTED = new Color(166, 197, 209)

  var playerX = 900.0
  var playerY = 1050.0
  var facingX = 0.0
  var facingY = -1.0
  var cameraX = 0.0
  var cameraY = 0.0
  var frames = 0L
  var secondsPlayed = 0.0
  var remainingSeconds = 360.0
  var started = false
  var paused = false
  var won = false
  var lost = false
  var glowMode = true
  var showMap = true
  var dashTime = 0.0
  var dashCooldown = 0.0
  var toast = "Find the six Cyber Blooms to awaken the Garden Portal."
  var toastTime = 5.0
  var glitchTime = 0.0
  var glitchActive = false
  var panel: GardenPanel = null
  var window: JFrame = null
  var gameTimer: Timer = null

  val portalX = 900.0
  val portalY = 235.0

  def clamp(v: Double, low: Double, high: Double): Double = math.max(low, math.min(high, v))
  def dist(x1: Double, y1: Double, x2: Double, y2: Double): Double = {
    val dx = x1 - x2
    val dy = y1 - y2
    math.sqrt(dx * dx + dy * dy)
  }
  def hueColor(hue: Int, saturation: Float = 0.82f, brightness: Float = 1.0f): Color =
    Color.getHSBColor((hue.toDouble / 360.0).toFloat, saturation, brightness)

  def showToast(text: String, duration: Double = 2.8): Unit = {
    toast = text
    toastTime = duration
    try { java.awt.Toolkit.getDefaultToolkit.beep() } catch { case _: Throwable => () }
  }

  def setupWorld(): Unit = {
    blooms.clear()
    blooms += new Bloom(590, 890, 166, "NEON ROSE")
    blooms += new Bloom(300, 735, 190, "PIXEL TULIP")
    blooms += new Bloom(835, 610, 138, "MINT ORCHID")
    blooms += new Bloom(1450, 500, 292, "GLITCH DAISY")
    blooms += new Bloom(1210, 360, 325, "CYBER LILY")
    blooms += new Bloom(900, 430, 48, "SPRING STAR")

    gardenFlowers.clear()
    trees.clear()
    particles.clear()
    val flowerZones = Array((120.0, 150.0, 650.0, 340.0), (1200.0, 140.0, 500.0, 300.0),
      (70.0, 1030.0, 650.0, 200.0), (1150.0, 930.0, 620.0, 260.0),
      (430.0, 380.0, 250.0, 170.0), (1420.0, 690.0, 280.0, 220.0),
      (620.0, 680.0, 270.0, 140.0), (1040.0, 480.0, 230.0, 100.0))
    var i = 0
    while (i < 145) {
      val zone = flowerZones(random.nextInt(flowerZones.length))
      val x = zone._1 + random.nextDouble() * zone._3
      val y = zone._2 + random.nextDouble() * zone._4
      val hue = Array(145, 164, 188, 282, 315, 48)(random.nextInt(6))
      gardenFlowers += new GardenFlower(x, y, 5.0 + random.nextDouble() * 8.0,
        hue, random.nextDouble() * 6.28, random.nextInt(9) == 0)
      i += 1
    }
    val treeData = Array(
      (135.0,180.0,1.12,150),(390.0,220.0,0.92,164),(740.0,145.0,0.85,142),
      (1110.0,155.0,0.92,162),(1605.0,170.0,1.12,154),(1770.0,410.0,0.95,168),
      (1735.0,900.0,1.12,152),(1550.0,1130.0,0.95,165),(1190.0,1110.0,0.92,150),
      (720.0,1150.0,1.06,163),(350.0,1120.0,1.04,152),(130.0,850.0,1.00,165),
      (530.0,430.0,0.82,152),(1050.0,760.0,0.90,166),(1640.0,720.0,0.90,150),
      (240.0,560.0,0.82,160),(1320.0,245.0,0.76,155),(650.0,980.0,0.88,145))
    treeData.foreach(t => trees += new GardenTree(t._1,t._2,t._3,t._4))
    var p = 0
    while (p < 90) {
      particles += new Particle(random.nextDouble() * WORLD_W, random.nextDouble() * WORLD_H,
        (random.nextDouble() - 0.5) * 0.7, -0.25 - random.nextDouble() * 0.7,
        1.5 + random.nextDouble() * 3.5, Array(150,168,185,285,320,48)(random.nextInt(6)),
        2.0 + random.nextDouble() * 7.0)
      p += 1
    }
  }

  def resetGame(): Unit = {
    playerX = 900.0; playerY = 1050.0
    facingX = 0.0; facingY = -1.0
    frames = 0L; secondsPlayed = 0.0; remainingSeconds = 360.0
    started = false; paused = false; won = false; lost = false
    glowMode = true; showMap = true
    dashTime = 0.0; dashCooldown = 0.0
    blooms.foreach(_.collected = false)
    showToast("Welcome to Cyber Bloom Garden! Press ENTER to start.", 4.5)
  }

  def collectedCount: Int = blooms.count(_.collected)

  def triggerDash(): Unit = {
    if (started && !paused && !won && !lost && dashCooldown <= 0.0) {
      dashTime = 0.22
      dashCooldown = 1.0
      showToast("CYBER DASH!", 0.75)
    }
  }

  def interact(): Unit = {
    if (!started || paused || won || lost) return
    val nearest = blooms.filter(!_.collected).sortBy(b => dist(playerX,playerY,b.x,b.y)).headOption
    nearest match {
      case Some(b) if dist(playerX, playerY, b.x, b.y) < 95.0 =>
        b.collected = true
        showToast("CYBER BLOOM RESTORED: " + b.label + "  [" + collectedCount + "/" + GOAL_COUNT + "]", 2.7)
        spawnBurst(b.x, b.y, b.hue, 24)
        if (collectedCount >= GOAL_COUNT) showToast("ALL SIX BLOOMS RESTORED! Reach the portal at the top of the garden.", 4.2)
      case _ if dist(playerX, playerY, portalX, portalY) < 125.0 && collectedCount >= GOAL_COUNT =>
        won = true
        showToast("GARDEN RESTORED! YOU CLEARED THE CYBER BLOOM EVENT!", 10.0)
      case _ if dist(playerX, playerY, portalX, portalY) < 125.0 =>
        showToast("PORTAL LOCKED: collect all six Cyber Blooms first.", 2.8)
      case _ => showToast("Move close to a glowing bloom or the Garden Portal, then press E.", 2.4)
    }
  }

  def spawnBurst(x: Double, y: Double, hue: Int, amount: Int): Unit = {
    var i = 0
    while (i < amount) {
      val a = random.nextDouble() * math.Pi * 2.0
      val speed = 25.0 + random.nextDouble() * 130.0
      particles += new Particle(x, y, math.cos(a)*speed, math.sin(a)*speed,
        2.0 + random.nextDouble()*4.0, hue, 0.5 + random.nextDouble()*1.2)
      i += 1
    }
  }

  def updateGame(dt: Double): Unit = {
    frames += 1
    if (toastTime > 0.0) toastTime = math.max(0.0, toastTime - dt)
    if (dashTime > 0.0) dashTime = math.max(0.0, dashTime - dt)
    if (dashCooldown > 0.0) dashCooldown = math.max(0.0, dashCooldown - dt)
    glitchTime -= dt
    if (glitchTime <= 0.0) {
      glitchTime = 1.8 + random.nextDouble()*3.6
      glitchActive = random.nextInt(5) == 0
    }
    particles.foreach { p =>
      p.x += p.vx * dt
      p.y += p.vy * dt
      p.life -= dt
      if (p.y < 0) p.y = WORLD_H
      if (p.x < 0) p.x = WORLD_W
      if (p.x > WORLD_W) p.x = 0
    }
    particles --= particles.filter(_.life <= 0.0)
    if (particles.length < 65) {
      particles += new Particle(random.nextDouble()*WORLD_W, WORLD_H-10,
        (random.nextDouble()-0.5)*18.0, -8.0-random.nextDouble()*23.0,
        1.5+random.nextDouble()*3.0, Array(150,170,188,285,318,48)(random.nextInt(6)), 3.5)
    }
    if (!started || paused || won || lost) return

    secondsPlayed += dt
    remainingSeconds = math.max(0.0, remainingSeconds-dt)
    if (remainingSeconds <= 0.0) {
      lost = true
      showToast("EVENT TIME EXPIRED - PRESS R TO TRY AGAIN", 12.0)
      return
    }

    var mx = 0.0
    var my = 0.0
    if (keys.contains(KeyEvent.VK_W) || keys.contains(KeyEvent.VK_UP)) my -= 1.0
    if (keys.contains(KeyEvent.VK_S) || keys.contains(KeyEvent.VK_DOWN)) my += 1.0
    if (keys.contains(KeyEvent.VK_A) || keys.contains(KeyEvent.VK_LEFT)) mx -= 1.0
    if (keys.contains(KeyEvent.VK_D) || keys.contains(KeyEvent.VK_RIGHT)) mx += 1.0
    val length = math.sqrt(mx*mx + my*my)
    if (length > 0.0) {
      mx /= length; my /= length
      facingX = mx; facingY = my
      val speed = if (dashTime > 0.0) 430.0 else 205.0
      playerX = clamp(playerX + mx*speed*dt, 60.0, WORLD_W-60.0)
      playerY = clamp(playerY + my*speed*dt, 60.0, WORLD_H-60.0)
    }
    if (collectedCount >= GOAL_COUNT && dist(playerX, playerY, portalX, portalY) < 82.0) {
      won = true
      showToast("GARDEN RESTORED! YOU CLEARED THE CYBER BLOOM EVENT!", 10.0)
      spawnBurst(portalX, portalY, 165, 70)
    }
    if (glitchActive && random.nextInt(8) == 0) {
      val b = blooms.filter(!_.collected).headOption
      b.foreach(x => { /* visual glitch is only atmospheric; no progress is removed */ })
    }
  }

  def drawGlow(g: Graphics2D, x: Int, y: Int, radius: Int, color: Color, alpha: Float): Unit = {
    val old = g.getComposite
    g.setComposite(AlphaComposite.SrcOver.derive(alpha))
    g.setColor(color)
    g.fillOval(x-radius, y-radius, radius*2, radius*2)
    g.setComposite(old)
  }

  def drawCentered(g: Graphics2D, text: String, x: Int, y: Int): Unit = {
    val width = g.getFontMetrics.stringWidth(text)
    g.drawString(text, x-width/2, y)
  }

  def screenX(x: Double): Int = math.round(x-cameraX).toInt
  def screenY(y: Double): Int = math.round(y-cameraY).toInt

  def drawPath(g: Graphics2D): Unit = {
    val oldStroke = g.getStroke
    val oldColor = g.getColor
    val oldComposite = g.getComposite
    val pts = Array((900.0,1080.0,900.0,890.0),(900.0,890.0,300.0,890.0),
      (300.0,890.0,300.0,610.0),(300.0,610.0,1450.0,610.0),
      (1450.0,610.0,1450.0,360.0),(1450.0,360.0,900.0,360.0),(900.0,360.0,900.0,250.0))
    g.setStroke(new BasicStroke(118.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND))
    g.setColor(new Color(10,28,40))
    pts.foreach(p => g.drawLine(screenX(p._1),screenY(p._2),screenX(p._3),screenY(p._4)))
    g.setStroke(new BasicStroke(88.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND))
    g.setComposite(AlphaComposite.SrcOver.derive(0.72f))
    g.setColor(new Color(31,76,80))
    pts.foreach(p => g.drawLine(screenX(p._1),screenY(p._2),screenX(p._3),screenY(p._4)))
    g.setStroke(new BasicStroke(3.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND))
    g.setColor(new Color(70,196,184,150))
    pts.foreach(p => g.drawLine(screenX(p._1),screenY(p._2),screenX(p._3),screenY(p._4)))
    g.setComposite(oldComposite)
    g.setStroke(oldStroke)
    g.setColor(oldColor)
  }

  def drawTree(g: Graphics2D, tree: GardenTree): Unit = {
    val x = screenX(tree.x); val y = screenY(tree.y)
    val s = tree.size
    if (x < -100 || y < -150 || x > START_W+100 || y > START_H+100) return
    drawGlow(g,x,y-28,(45*s).toInt,hueColor(tree.hue),0.07f)
    g.setColor(new Color(54,66,56))
    g.fillRoundRect((x-8*s).toInt,y-(35*s).toInt,(16*s).toInt,(54*s).toInt,7,7)
    val canopy = hueColor(tree.hue,0.60f,0.52f)
    g.setColor(canopy)
    g.fillOval((x-34*s).toInt,y-(92*s).toInt,(68*s).toInt,(70*s).toInt)
    g.setColor(hueColor(tree.hue,0.58f,0.72f))
    g.fillOval((x-26*s).toInt,y-(102*s).toInt,(47*s).toInt,(48*s).toInt)
    g.setColor(new Color(162,255,218,130))
    g.drawArc((x-27*s).toInt,y-(99*s).toInt,(52*s).toInt,(49*s).toInt,40,115)
    g.setColor(new Color(14,24,38,90))
    g.fillOval((x-39*s).toInt,y-(28*s).toInt,(78*s).toInt,(18*s).toInt)
  }

  def drawSmallFlower(g: Graphics2D, x: Int, y: Int, size: Double, hue: Int, phase: Double, special: Boolean): Unit = {
    if (x < -40 || y < -40 || x > START_W+40 || y > START_H+40) return
    val color = hueColor(hue, if(special) 0.70f else 0.64f, 1.0f)
    val pulse = 0.82 + 0.18*math.sin(frames*0.065 + phase)
    val r = math.max(2,(size*pulse).toInt)
    if (special && glowMode) drawGlow(g,x,y,r*5,color,0.12f)
    g.setColor(new Color(28,105,76))
    g.setStroke(new BasicStroke(2.0f))
    g.drawLine(x,y+2,x,y+r*2+3)
    val old = g.getTransform
    g.rotate(frames*0.004+phase,x.toDouble,y.toDouble)
    g.setColor(color)
    var i=0
    val petals = if(special) 8 else 5
    while(i<petals) {
      val a=i*math.Pi*2.0/petals
      val px=x+math.round(math.cos(a)*r*0.78).toInt
      val py=y+math.round(math.sin(a)*r*0.78).toInt
      g.fillOval(px-r/2,py-r/2,math.max(3,r),math.max(3,r))
      i+=1
    }
    g.setTransform(old)
    g.setColor(if(special) GOLD else new Color(255,239,181))
    g.fillOval(x-r/3,y-r/3,math.max(3,2*r/3),math.max(3,2*r/3))
  }

  def drawBloom(g: Graphics2D, b: Bloom): Unit = {
    val x=screenX(b.x); val y=screenY(b.y)
    if (b.collected || x < -100 || y < -100 || x > START_W+100 || y > START_H+100) return
    val color=hueColor(b.hue,0.76f,1.0f)
    val pulse=1.0+0.14*math.sin(frames*0.09+b.hue)
    val r=(15*pulse).toInt
    if(glowMode) {
      drawGlow(g,x,y,r*5,color,0.09f)
      drawGlow(g,x,y,r*3,CYAN,0.07f)
    }
    g.setColor(new Color(12,25,42,210))
    g.fillOval(x-r-7,y-r-7,(r+7)*2,(r+7)*2)
    g.setColor(color)
    g.setStroke(new BasicStroke(2.0f))
    g.drawOval(x-r-8,y-r-8,(r+8)*2,(r+8)*2)
    drawSmallFlower(g,x,y,r.toDouble,colorHueValue(b.hue),b.hue*0.01,true)
    g.setFont(new Font("SansSerif",Font.BOLD,10))
    g.setColor(WHITE)
    drawCentered(g,b.label, x, y-r-22)
    g.setColor(CYAN)
    drawCentered(g,"E  /  COLLECT",x,y+r+25)
    if(glitchActive) {
      g.setColor(new Color(255,65,197,150))
      g.fillRect(x-r-12,y-2,r*2+24,2)
      g.setColor(new Color(59,245,255,140))
      g.fillRect(x-r-6,y+5,r*2+12,2)
    }
  }

  def colorHueValue(hue: Int): Int = hue

  def drawPortal(g: Graphics2D): Unit = {
    val x=screenX(portalX); val y=screenY(portalY)
    val ready=collectedCount>=GOAL_COUNT
    val pulse=1.0+math.sin(frames*0.05)*0.06
    val w=(118*pulse).toInt; val h=(152*pulse).toInt
    if(glowMode) drawGlow(g,x,y,105,if(ready) MINT else PURPLE,0.10f)
    g.setColor(new Color(8,13,31,220))
    g.fillOval(x-w/2,y-h/2,w,h)
    g.setColor(if(ready) MINT else PURPLE)
    g.setStroke(new BasicStroke(5.0f))
    g.drawOval(x-w/2,y-h/2,w,h)
    g.setColor(new Color(56,232,236,100))
    g.setStroke(new BasicStroke(2.0f))
    g.drawOval(x-w/2+11,y-h/2+12,w-22,h-24)
    g.setColor(new Color(201,123,255,90))
    g.drawOval(x-w/2+23,y-h/2+22,w-46,h-44)
    var i=0
    while(i<7) {
      val a=frames*0.027+i*math.Pi*2.0/7.0
      val px=x+math.round(math.cos(a)*42).toInt
      val py=y+math.round(math.sin(a)*60).toInt
      g.setColor(if(i%2==0) CYAN else PINK)
      g.fillOval(px-3,py-3,6,6)
      i+=1
    }
    g.setFont(new Font("SansSerif",Font.BOLD,12))
    g.setColor(if(ready) MINT else WHITE)
    drawCentered(g,if(ready) "PORTAL READY" else "GARDEN PORTAL",x,y+h/2+23)
  }

  def drawPlayer(g: Graphics2D): Unit = {
    val x=screenX(playerX); val y=screenY(playerY)
    val bob=math.sin(frames*0.22)*2.3
    if(glowMode) drawGlow(g,x,y,38,CYAN,0.09f)
    g.setColor(new Color(0,0,0,100))
    g.fillOval(x-20,y+16,40,12)
    // boots / legs
    g.setColor(new Color(24,40,65))
    g.fillRoundRect(x-13,y+2+(bob.toInt),10,21,5,5)
    g.fillRoundRect(x+3,y+2-(bob.toInt),10,21,5,5)
    g.setColor(CYAN)
    g.fillRoundRect(x-14,y+17,12,6,3,3)
    g.fillRoundRect(x+2,y+17,12,6,3,3)
    // body and backpack
    g.setColor(new Color(23,46,83))
    g.fillRoundRect(x-17,y-23+bob.toInt,34,33,12,12)
    g.setColor(new Color(44,182,201))
    g.fillRoundRect(x-14,y-20+bob.toInt,28,26,9,9)
    g.setColor(new Color(170,255,238))
    g.fillRoundRect(x-5,y-18+bob.toInt,10,20,4,4)
    g.setColor(PURPLE)
    g.fillRoundRect(x+12,y-18+bob.toInt,8,21,5,5)
    // head / visor
    g.setColor(new Color(232,199,166))
    g.fillOval(x-11,y-43+bob.toInt,22,23)
    g.setColor(new Color(25,38,61))
    g.fillRoundRect(x-13,y-39+bob.toInt,26,10,7,7)
    g.setColor(CYAN)
    g.fillRoundRect(x-8,y-36+bob.toInt,16,4,3,3)
    // animated direction marker
    g.setColor(new Color(255,255,255,190))
    g.drawLine(x,y-48+bob.toInt,x+(facingX*15).toInt,y-48+(facingY*15).toInt+bob.toInt)
    if(dashTime>0) {
      g.setColor(new Color(91,250,245,130))
      g.setStroke(new BasicStroke(3.0f))
      g.drawLine(x-(facingX*42).toInt,y+8-(facingY*42).toInt,x,y+8)
    }
  }

  def drawParticles(g: Graphics2D): Unit = {
    particles.foreach { p =>
      val x=screenX(p.x); val y=screenY(p.y)
      if (x >= -5 && y >= -5 && x < START_W + 5 && y < START_H + 5) {
        val alpha=clamp(p.life/2.0,0.0,0.8).toFloat
        val old=g.getComposite
        g.setComposite(AlphaComposite.SrcOver.derive(alpha))
        g.setColor(hueColor(p.hue,0.55f,1.0f))
        g.fillOval(x,y,math.max(2,p.size.toInt),math.max(2,p.size.toInt))
        g.setComposite(old)
      }
    }
  }

  def drawHUD(g: Graphics2D, w: Int, h: Int): Unit = {
    val old=g.getComposite
    g.setComposite(AlphaComposite.SrcOver.derive(0.88f))
    g.setColor(new Color(7,15,31))
    g.fillRoundRect(16,15,465,93,20,20)
    g.setColor(new Color(61,226,213,180))
    g.drawRoundRect(16,15,465,93,20,20)
    g.setComposite(old)
    g.setFont(new Font("SansSerif",Font.BOLD,19))
    g.setColor(CYAN)
    g.drawString("CYBER BLOOM",31,43)
    g.setFont(new Font("SansSerif",Font.BOLD,11))
    g.setColor(WHITE)
    g.drawString("GLITCH IN THE GARDEN  /  SPRING SEASON",31,62)
    g.setColor(MUTED)
    g.drawString("BLOOMS RESTORED  " + collectedCount + " / " + GOAL_COUNT,31,86)
    val barX=206; val barY=76; val barW=245; val barH=9
    g.setColor(new Color(35,56,73)); g.fillRoundRect(barX,barY,barW,barH,8,8)
    g.setColor(if(collectedCount==GOAL_COUNT) MINT else PINK)
    g.fillRoundRect(barX,barY,math.max(0,(barW*collectedCount/GOAL_COUNT)),barH,8,8)

    g.setColor(new Color(7,15,31,220))
    g.fillRoundRect(w-190,18,170,74,17,17)
    g.setColor(new Color(61,226,213,180))
    g.drawRoundRect(w-190,18,170,74,17,17)
    val mins=(remainingSeconds.toInt/60)
    val secs=remainingSeconds.toInt%60
    g.setFont(new Font("Monospaced",Font.BOLD,22))
    g.setColor(if(remainingSeconds<45) PINK else GOLD)
    g.drawString(f"$mins%02d:$secs%02d",w-168,52)
    g.setFont(new Font("SansSerif",Font.PLAIN,10))
    g.setColor(MUTED)
    g.drawString("EVENT TIME LEFT",w-166,72)

    val bottomY=h-57
    g.setColor(new Color(6,13,27,225))
    g.fillRoundRect(15,bottomY,w-30,42,14,14)
    g.setColor(new Color(71,153,177,160))
    g.drawRoundRect(15,bottomY,w-30,42,14,14)
    g.setFont(new Font("SansSerif",Font.BOLD,11))
    g.setColor(WHITE)
    g.drawString("WASD / ARROWS  MOVE",30,bottomY+17)
    g.setColor(CYAN); g.drawString("E  INTERACT",220,bottomY+17)
    g.setColor(PINK); g.drawString("SPACE  DASH",335,bottomY+17)
    g.setColor(GOLD); g.drawString("F  GLOW",458,bottomY+17)
    g.setColor(MUTED); g.drawString("M  MAP   |   ESC  PAUSE   |   R  RESTART",565,bottomY+17)

    if(toastTime>0.0) {
      val tw=math.min(w-60,math.max(400,g.getFontMetrics.stringWidth(toast)+42))
      val tx=(w-tw)/2
      g.setColor(new Color(8,18,34,230))
      g.fillRoundRect(tx,h-103,tw,34,15,15)
      g.setColor(new Color(71,238,220,170))
      g.drawRoundRect(tx,h-103,tw,34,15,15)
      g.setFont(new Font("SansSerif",Font.BOLD,12))
      g.setColor(WHITE)
      drawCentered(g,toast,w/2,h-82)
    }
    if(showMap) drawMiniMap(g,w)
    if(glitchActive && frames%4<2 && started && !paused && !won && !lost) {
      val oldC=g.getComposite
      g.setComposite(AlphaComposite.SrcOver.derive(0.10f))
      g.setColor(PINK); g.fillRect(0,116,w,3)
      g.setColor(CYAN); g.fillRect(0,120,w,2)
      g.setComposite(oldC)
    }
  }

  def drawMiniMap(g: Graphics2D,w: Int): Unit = {
    val x=w-190; val y=110; val mw=168; val mh=116
    g.setColor(new Color(6,14,29,210)); g.fillRoundRect(x,y,mw,mh,12,12)
    g.setColor(new Color(60,211,206,160)); g.drawRoundRect(x,y,mw,mh,12,12)
    def mx(v: Double): Int = x+8+(v/WORLD_W* (mw-16)).toInt
    def my(v: Double): Int = y+8+(v/WORLD_H*(mh-16)).toInt
    g.setStroke(new BasicStroke(4.0f)); g.setColor(new Color(48,106,111))
    val paths=Array((900.0,1080.0,900.0,890.0),(900.0,890.0,300.0,890.0),(300.0,890.0,300.0,610.0),
      (300.0,610.0,1450.0,610.0),(1450.0,610.0,1450.0,360.0),(1450.0,360.0,900.0,360.0),(900.0,360.0,900.0,250.0))
    paths.foreach(p=>g.drawLine(mx(p._1),my(p._2),mx(p._3),my(p._4)))
    blooms.filter(!_.collected).foreach(b=>{g.setColor(hueColor(b.hue));g.fillOval(mx(b.x)-2,my(b.y)-2,5,5)})
    g.setColor(MINT);g.fillOval(mx(portalX)-4,my(portalY)-4,8,8)
    g.setColor(WHITE);g.fillOval(mx(playerX)-3,my(playerY)-3,6,6)
    g.setFont(new Font("SansSerif",Font.BOLD,9));g.setColor(MUTED);g.drawString("GARDEN MAP",x+9,y+12)
  }

  def drawIntroOverlay(g: Graphics2D,w: Int,h: Int): Unit = {
    g.setColor(new Color(3,8,22,188))
    g.fillRect(0,0,w,h)
    val cx=w/2; val cy=h/2
    drawGlow(g,cx,cy-90,180,PURPLE,0.08f)
    g.setFont(new Font("SansSerif",Font.BOLD,17)); g.setColor(MINT)
    drawCentered(g,"SPRING SEASON EVENT  /  LIMITED-TIME GARDEN QUEST",cx,cy-185)
    g.setFont(new Font("SansSerif",Font.BOLD,42)); g.setColor(CYAN)
    drawCentered(g,"CYBER BLOOM",cx,cy-126)
    g.setFont(new Font("SansSerif",Font.BOLD,29)); g.setColor(PINK)
    drawCentered(g,"GLITCH IN THE GARDEN",cx,cy-85)
    g.setFont(new Font("SansSerif",Font.PLAIN,15)); g.setColor(WHITE)
    drawCentered(g,"A corrupted spring has hidden six Cyber Blooms across the garden.",cx,cy-40)
    drawCentered(g,"Restore the flowers, avoid the glitch, and awaken the Garden Portal.",cx,cy-17)
    val bw=260; val bh=54; val bx=cx-bw/2; val by=cy+25
    g.setColor(new Color(17,55,72,240));g.fillRoundRect(bx,by,bw,bh,20,20)
    g.setStroke(new BasicStroke(2.5f));g.setColor(CYAN);g.drawRoundRect(bx,by,bw,bh,20,20)
    g.setFont(new Font("SansSerif",Font.BOLD,18));g.setColor(WHITE)
    drawCentered(g,"ENTER THE GARDEN",cx,by+34)
    g.setFont(new Font("SansSerif",Font.PLAIN,12));g.setColor(MUTED)
    drawCentered(g,"ENTER / SPACE / CLICK TO START",cx,by+bh+30)
    drawCentered(g,"Controls: WASD move  ?  E collect  ?  SPACE dash  ?  F glow  ?  M map",cx,by+bh+54)
    g.setColor(new Color(255,255,255,120));g.setFont(new Font("SansSerif",Font.PLAIN,10))
    drawCentered(g,"ORIGINAL SCALA SWING MINI-GAME  ?  OFFLINE  ?  NO EXTERNAL ASSETS",cx,h-18)
  }

  def drawEndOverlay(g: Graphics2D,w: Int,h: Int): Unit = {
    g.setColor(new Color(3,8,22,205));g.fillRect(0,0,w,h)
    val title=if(won) "SPRING RESTORED!" else if(lost) "THE GLITCH WON THIS ROUND" else "PAUSED"
    g.setFont(new Font("SansSerif",Font.BOLD,36));g.setColor(if(won) MINT else if(lost) PINK else CYAN)
    drawCentered(g,title,w/2,h/2-46)
    g.setFont(new Font("SansSerif",Font.PLAIN,16));g.setColor(WHITE)
    val subtitle=if(won) "You gathered all six Cyber Blooms and opened the Garden Portal." else if(lost) "Time ran out. The garden can still be restored on another attempt." else "The garden is waiting. Press ESC to continue."
    drawCentered(g,subtitle,w/2,h/2-12)
    g.setFont(new Font("SansSerif",Font.BOLD,15));g.setColor(GOLD)
    drawCentered(g,"PRESS R TO RESTART",w/2,h/2+35)
  }

  final class GardenPanel extends JPanel {
    setPreferredSize(new Dimension(START_W,START_H))
    setBackground(BG_TOP)
    setFocusable(true)
    setDoubleBuffered(true)
    setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR))

    addKeyListener(new KeyAdapter {
      override def keyPressed(e: KeyEvent): Unit = {
        val k=e.getKeyCode
        keys += k
        if(!started && (k==KeyEvent.VK_ENTER || k==KeyEvent.VK_SPACE)) {
          started=true; paused=false; showToast("Quest started! Restore all six Cyber Blooms.",3.2)
        } else if(k==KeyEvent.VK_E) interact()
        else if(k==KeyEvent.VK_SPACE && started) triggerDash()
        else if(k==KeyEvent.VK_F) glowMode = !glowMode
        else if(k==KeyEvent.VK_M) showMap = !showMap
        else if(k==KeyEvent.VK_ESCAPE && started && !won && !lost) paused = !paused
        else if(k==KeyEvent.VK_R) resetGame()
      }
      override def keyReleased(e: KeyEvent): Unit = { keys -= e.getKeyCode }
    })
    addMouseListener(new MouseAdapter {
      override def mouseClicked(e: MouseEvent): Unit = {
        requestFocusInWindow()
        if(!started) {started=true; showToast("Quest started! Restore all six Cyber Blooms.",3.2)}
        else if(!paused && !won && !lost) interact()
      }
    })

    override protected def paintComponent(graphics: Graphics): Unit = {
      super.paintComponent(graphics)
      val g=graphics.create().asInstanceOf[Graphics2D]
      g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON)
      g.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY)
      val w=getWidth; val h=getHeight
      g.setPaint(new GradientPaint(0f,0f,BG_TOP,0f,h.toFloat,BG_BOTTOM))
      g.fillRect(0,0,w,h)
      cameraX=clamp(playerX-w/2.0,0.0,WORLD_W-w)
      cameraY=clamp(playerY-h/2.0,0.0,WORLD_H-h)
      drawGround(g,w,h)
      drawPath(g)
      trees.foreach(t=>drawTree(g,t))
      gardenFlowers.foreach(f=>drawSmallFlower(g,screenX(f.x),screenY(f.y),f.size,f.hue,f.phase,f.glitch))
      blooms.foreach(b=>drawBloom(g,b))
      drawPortal(g)
      drawParticles(g)
      drawPlayer(g)
      if(started) drawHUD(g,w,h)
      if(!started) drawIntroOverlay(g,w,h)
      else if(paused || won || lost) drawEndOverlay(g,w,h)
      g.dispose()
    }
  }

  def drawGround(g: Graphics2D,w: Int,h: Int): Unit = {
    g.setColor(new Color(17,49,53))
    g.fillRect(-cameraX.toInt,-cameraY.toInt,WORLD_W,WORLD_H)
    // Glowing ground grid in world coordinates.
    val old=g.getComposite
    g.setComposite(AlphaComposite.SrcOver.derive(0.11f))
    g.setColor(new Color(59,211,202))
    val step=80
    var x=(cameraX/step).toInt*step
    while(x<cameraX+w+step) {g.drawLine((x-cameraX).toInt,0,(x-cameraX).toInt,h);x+=step}
    var y=(cameraY/step).toInt*step
    while(y<cameraY+h+step) {g.drawLine(0,(y-cameraY).toInt,w,(y-cameraY).toInt);y+=step}
    g.setComposite(old)
    // softly illuminated flower-bed islands
    val beds=Array((250.0,260.0,460.0,260.0,160),(1310.0,255.0,470.0,260.0,285),
      (260.0,1080.0,500.0,180.0,150),(1350.0,1050.0,460.0,280.0,165),
      (605.0,440.0,310.0,190.0,318),(1470.0,750.0,310.0,260.0,48),(1090.0,500.0,280.0,170.0,188))
    beds.foreach { b =>
      val c=hueColor(b._5,0.58f,0.75f)
      g.setColor(new Color(c.getRed,c.getGreen,c.getBlue,18))
      g.fillOval(screenX(b._1).toInt-(b._3/2).toInt,screenY(b._2).toInt-(b._4/2).toInt,b._3.toInt,b._4.toInt)
      g.setColor(new Color(c.getRed,c.getGreen,c.getBlue,70))
      g.drawOval(screenX(b._1).toInt-(b._3/2).toInt,screenY(b._2).toInt-(b._4/2).toInt,b._3.toInt,b._4.toInt)
    }
    // slim cyber fence markers at the edge of the map
    g.setColor(new Color(70,222,207,100))
    g.setStroke(new BasicStroke(3.0f))
    g.drawRect(screenX(35).toInt,screenY(35).toInt,WORLD_W-70,WORLD_H-70)
  }

  def main(args: Array[String]): Unit = {
    setupWorld()
    SwingUtilities.invokeLater(new Runnable {
      override def run(): Unit = {
        window = new JFrame(APP_TITLE)
        panel = new GardenPanel()
        window.setContentPane(panel)
        window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE)
        window.setMinimumSize(new Dimension(900,620))
        window.setSize(START_W,START_H)
        window.setLocationRelativeTo(null)
        window.setVisible(true)
        panel.requestFocusInWindow()
        gameTimer = new Timer(33,new ActionListener {
          override def actionPerformed(e: ActionEvent): Unit = {
            updateGame(0.033)
            if(panel!=null) panel.repaint()
          }
        })
        gameTimer.start()
      }
    })
  }
}

SpringSeasonCyberBloomGlitch.main(Array[String]())