Code Sketch


alok
By: Mhalsakant School
Category: Programming
import scala.collection.mutable.ArrayBuffer

cleari()
originBottomLeft()

// ============================================================
// HAUNTED MANSION - SPOOKY GHOST ESCAPE GAME V2.1 (FIXED)
// ============================================================

var globalTime = 0.0
var currentStoryStage = 0 // 0: Welcome, 1: Graveyard, 2: Gameplay, 3: Win Screen

// Player Position (Ghost Hunter)
var playerX = cwidth / 2.0
var playerY = 100.0
var playerDir = "UP"
var score = 0
var lives = 3
val winningScoreTarget = 10 // Target score to win the game!

// Ghost Position (Spooky Enemy)
var ghostX = randomDouble(100, cwidth - 100)
var ghostY = randomDouble(100, cheight - 100)

// Multiple Targets (Cursed Skulls & Magic Potions)
var targetX = randomDouble(80, cwidth - 80)
var targetY = randomDouble(80, cheight - 80)
var targetType = 1 // 1: Skull (1 pt), 2: Magic Potion (2 pts)

// Spooky Sound Setup
var audioEnabled = false
try {
  setNoteInstrument(Instrument.PIANO)
  audioEnabled = true
} catch {
  case _: Exception => audioEnabled = false
}

def playSpookySound(note: Int, duration: Int): Unit = {
  if (audioEnabled) {
    try { playNote(note, duration) } catch { case _: Exception => }
  }
}

// Spooky Particles
case class SpookyParticle(var x: Double, var y: Double, var vx: Double, var vy: Double, var size: Double)
val spookyParticles = ArrayBuffer.empty[SpookyParticle]

def spawnSpookyParticles(x: Double, y: Double, count: Int): Unit = {
  var i = 0
  while (i < count && spookyParticles.length < 200) {
    spookyParticles.append(SpookyParticle(x, y, randomDouble(-2.0, 2.0), randomDouble(-2.0, 2.0), randomDouble(2.0, 5.0)))
    i += 1
  }
}

// Main Game Loop
animateWithState(0.0) { angle =>
  erasePictures()
  globalTime += 0.05

  // Update spooky particles
  spookyParticles.foreach { p =>
    p.x += p.vx
    p.y += p.vy
  }

  // Dark, eerie background
  setBackground(Color(10, 10, 20))

  if (currentStoryStage == 0) {
    // --- STAGE 0: WELCOME SCREEN ---
    val titlePic = Picture.text("HAUNTED MANSION: TARGET SURVIVAL", 26)
    titlePic.setPenColor(Color(180, 0, 0))
    titlePic.setPosition(cwidth / 2.0 - 210, cheight - 120)
    draw(titlePic)

    val subPic = Picture.text(s"Collect $winningScoreTarget Cursed Targets while escaping the Ghost!", 14)
    subPic.setPenColor(Color(150, 150, 150))
    subPic.setPosition(cwidth / 2.0 - 200, cheight - 160)
    draw(subPic)

    val prompt = Picture.text("Click anywhere or Press Enter to Start", 14)
    prompt.setPenColor(Color(200, 200, 200))
    prompt.setPosition(cwidth / 2.0 - 150, 60)
    draw(prompt)

  } else if (currentStoryStage == 1) {
    // --- STAGE 1: GRAVEYARD CORRIDOR ---
    val ground = Picture.rect(cwidth, 100)
    ground.setFillColor(Color(25, 25, 35))
    ground.setPenColor(Color(50, 50, 70))
    ground.setPosition(0, 0)
    draw(ground)

    var t = 50.0
    while (t < cwidth) {
      val stone = Picture.rect(30, 45)
      stone.setFillColor(Color(70, 70, 80))
      stone.setPenColor(Color(100, 100, 110))
      stone.setPosition(t, 80)
      draw(stone)
      t += 120
    }

    val warningText = Picture.text("=== COLLECT TARGETS TO SURVIVE ===", 18)
    warningText.setPenColor(Color(220, 20, 60))
    warningText.setPosition(cwidth / 2.0 - 170, cheight - 60)
    draw(warningText)

    val enterGameText = Picture.text("Press Enter to Begin Game!", 16)
    enterGameText.setPenColor(Color(200, 200, 200))
    enterGameText.setPosition(cwidth / 2.0 - 110, cheight - 100)
    draw(enterGameText)

  } else if (currentStoryStage == 2) {
    // --- STAGE 2: GAMEPLAY ---

    // Player movement
    if (playerDir == "RIGHT" && playerX < cwidth - 20) playerX += 4.0
    if (playerDir == "LEFT" && playerX > 20) playerX -= 4.0
    if (playerDir == "UP" && playerY < cheight - 20) playerY += 4.0
    if (playerDir == "DOWN" && playerY > 20) playerY -= 4.0

    // Ghost AI chases player
    if (ghostX < playerX) ghostX += 1.6 else ghostX -= 1.6
    if (ghostY < playerY) ghostY += 1.6 else ghostY -= 1.6

    // Check collision with Target
    val targetDist = math.hypot(playerX - targetX, playerY - targetY)
    if (targetDist < 25.0) {
      score += targetType 
      spawnSpookyParticles(targetX, targetY, 15)
      playSpookySound(55, 200)

      // Respawn target at new random location with random type
      targetX = randomDouble(50, cwidth - 50)
      targetY = randomDouble(50, cheight - 50)
      targetType = if (randomBoolean) 2 else 1

      // Check Win Condition
      if (score >= winningScoreTarget) {
        currentStoryStage = 3 // Move to Win Screen
      }
    }

    // Check collision with Ghost
    val ghostDist = math.hypot(playerX - ghostX, playerY - ghostY)
    if (ghostDist < 20.0) {
      lives -= 1
      ghostX = randomDouble(50, cwidth - 50)
      ghostY = randomDouble(50, cheight - 50)
      playSpookySound(30, 400)
      if (lives <= 0) {
        score = 0
        lives = 3 // Reset on game over
      }
    }

    // Draw Target (Skull if type 1, Glowing Potion if type 2) - FIXED SYNTAX HERE
    val targetPic = Picture.circle(if (targetType == 2) 12.0 else 9.0)
    targetPic.setFillColor(if (targetType == 2) Color(0, 255, 128) else Color(220, 220, 220))
    targetPic.setPenColor(Color(255, 255, 255))
    targetPic.setPosition(targetX, targetY)
    draw(targetPic)

    // Draw Ghost
    val ghostBody = Picture.circle(18.0)
    ghostBody.setFillColor(Color(150, 150, 200, 150))
    ghostBody.setPenColor(Color(255, 255, 255))
    ghostBody.setPosition(ghostX, ghostY)
    draw(ghostBody)

    // Draw Player
    val player = Picture.circle(14.0)
    player.setFillColor(Color(0, 200, 255))
    player.setPenColor(Color(255, 255, 255))
    player.setPosition(playerX, playerY)
    draw(player)

    // Draw UI (Score, Target & Lives)
    val uiText = Picture.text(s"Score: $score / $winningScoreTarget | Lives: $lives", 16)
    uiText.setPenColor(Color(255, 50, 50))
    uiText.setPosition(40, cheight - 40)
    draw(uiText)

    val controls = Picture.text("Use W, A, S, D to Collect Targets & Escape Ghost!", 14)
    controls.setPenColor(Color(180, 180, 180))
    controls.setPosition(40, cheight - 70)
    draw(controls)

  } else {
    // --- STAGE 3: WIN SCREEN ---
    val winText = Picture.text("CONGRATULATIONS! YOU ESCAPED THE HAUNTED MANSION!", 20)
    winText.setPenColor(Color(0, 255, 120))
    winText.setPosition(cwidth / 2.0 - 250, cheight / 2.0 + 20)
    draw(winText)

    val restartText = Picture.text("Press Enter or Click to Play Again", 14)
    restartText.setPenColor(Color(200, 200, 200))
    restartText.setPosition(cwidth / 2.0 - 130, cheight / 2.0 - 30)
    draw(restartText)
  }

  angle + 1.0
}

// Mouse Click to advance stages or restart
onMouseClick { (x, y) =>
  if (currentStoryStage == 0) {
    currentStoryStage = 1
  } else if (currentStoryStage == 1) {
    currentStoryStage = 2
    spawnSpookyParticles(cwidth / 2.0, cheight / 2.0, 25)
  } else if (currentStoryStage == 3) {
    score = 0
    lives = 3
    currentStoryStage = 2
  }
}

// Keyboard Controls
onKeyPress { k =>
  if (currentStoryStage < 2 || currentStoryStage == 3) {
    if (k == '\n' || k == '\r') {
      if (currentStoryStage == 0) {
        currentStoryStage = 1
      } else if (currentStoryStage == 1) {
        currentStoryStage = 2
        spawnSpookyParticles(cwidth / 2.0, cheight / 2.0, 25)
      } else if (currentStoryStage == 3) {
        score = 0
        lives = 3
        currentStoryStage = 2
      }
    }
  } else {
    if (k == 'd' || k == 'D') playerDir = "RIGHT"
    else if (k == 'a' || k == 'A') playerDir = "LEFT"
    else if (k == 'w' || k == 'W') playerDir = "UP"
    else if (k == 's' || k == 'S') playerDir = "DOWN"
  }
}

println("=== HAUNTED MANSION V2 LOADED SUCCESSFULLY ===")