Code Sketch
Bixuu ShadowfallEternalCurseEvent8
Category: Programming
import java.awt.{BasicStroke, BorderLayout, Color, Dimension, Font, Graphics, Graphics2D, GradientPaint, RenderingHints}
import java.awt.event.{ActionEvent, ActionListener, KeyAdapter, KeyEvent, MouseAdapter, MouseEvent}
import javax.swing.{JButton, JFrame, JLabel, JPanel, JTextField, SwingConstants, Timer, WindowConstants}
import scala.collection.mutable.ArrayBuffer
object ShadowfallEternalCurseEvent8 {
def main(args: Array[String]): Unit = {
javax.swing.SwingUtilities.invokeLater(new Runnable {
def run(): Unit = openGame()
})
}
def openGame(): Unit = {
val frame = new JFrame("INFINITY REALMS SEASON 08 - SHADOWFALL: ETERNAL CURSE")
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE)
frame.setResizable(false)
val login = new ShadowfallLoginPanel((playerName: String) => {
val game = new ShadowfallGamePanel(playerName)
frame.setContentPane(game)
frame.pack()
frame.setLocationRelativeTo(null)
game.requestFocusInWindow()
game.startGame()
})
frame.setContentPane(login)
frame.pack()
frame.setLocationRelativeTo(null)
frame.setVisible(true)
}
}
class ShadowfallLoginPanel(onStart: String => Unit) extends JPanel {
setPreferredSize(new Dimension(960, 680))
setLayout(null)
setBackground(new Color(12, 10, 27))
val title = new JLabel("SHADOWFALL", SwingConstants.CENTER)
title.setFont(new Font("Serif", Font.BOLD, 50))
title.setForeground(new Color(224, 211, 255))
title.setBounds(180, 105, 600, 70)
add(title)
val subtitle = new JLabel("ETERNAL CURSE | INFINITY REALMS SEASON 08", SwingConstants.CENTER)
subtitle.setFont(new Font("SansSerif", Font.BOLD, 18))
subtitle.setForeground(new Color(168, 142, 220))
subtitle.setBounds(150, 180, 660, 35)
add(subtitle)
val story = new JLabel("Explore the haunted realms, collect Moon Sigils and break the Eternal Curse.", SwingConstants.CENTER)
story.setFont(new Font("SansSerif", Font.PLAIN, 16))
story.setForeground(new Color(206, 198, 225))
story.setBounds(100, 240, 760, 32)
add(story)
val nameLabel = new JLabel("ENTER YOUR EXPLORER NAME", SwingConstants.CENTER)
nameLabel.setFont(new Font("SansSerif", Font.BOLD, 16))
nameLabel.setForeground(new Color(204, 188, 242))
nameLabel.setBounds(300, 330, 360, 30)
add(nameLabel)
val nameField = new JTextField("Explorer")
nameField.setFont(new Font("SansSerif", Font.PLAIN, 20))
nameField.setHorizontalAlignment(SwingConstants.CENTER)
nameField.setBounds(330, 370, 300, 42)
add(nameField)
val startButton = new JButton("ENTER THE SHADOW REALM")
startButton.setFont(new Font("SansSerif", Font.BOLD, 16))
startButton.setForeground(Color.WHITE)
startButton.setBackground(new Color(94, 62, 145))
startButton.setFocusPainted(false)
startButton.setBounds(330, 440, 300, 48)
startButton.addActionListener(new ActionListener {
def actionPerformed(e: ActionEvent): Unit = {
var chosen = nameField.getText.trim
if (chosen.length == 0) chosen = "Explorer"
onStart(chosen)
}
})
add(startButton)
val controls = new JLabel("WASD / ARROWS: MOVE SPACE: DASH F: LANTERN PULSE Q: AURA E: INTERACT", SwingConstants.CENTER)
controls.setFont(new Font("SansSerif", Font.PLAIN, 12))
controls.setForeground(new Color(151, 139, 179))
controls.setBounds(60, 585, 840, 25)
add(controls)
val hint = new JLabel("Offline adventure - Progress stays in this game session", SwingConstants.CENTER)
hint.setFont(new Font("SansSerif", Font.PLAIN, 12))
hint.setForeground(new Color(112, 104, 139))
hint.setBounds(200, 615, 560, 22)
add(hint)
override def paintComponent(g: Graphics): Unit = {
super.paintComponent(g)
val g2 = g.asInstanceOf[Graphics2D]
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
g2.setPaint(new GradientPaint(0, 0, new Color(9, 8, 24), 0, getHeight, new Color(47, 25, 70)))
g2.fillRect(0, 0, getWidth, getHeight)
var i = 0
while (i < 65) {
val x = (i * 149 + 31) % getWidth
val y = (i * 83 + 19) % getHeight
g2.setColor(new Color(182, 160, 230, 90))
g2.fillOval(x, y, 2 + (i % 3), 2 + (i % 3))
i += 1
}
g2.setColor(new Color(100, 74, 144, 80))
g2.fillOval(350, 5, 260, 260)
g2.setColor(new Color(15, 11, 31))
g2.fillOval(405, 5, 260, 260)
}
}
class ShadowfallGamePanel(val playerName: String) extends JPanel {
setPreferredSize(new Dimension(960, 680))
setBackground(new Color(16, 13, 30))
setFocusable(true)
class Sigil(val x: Int, val y: Int, var collected: Boolean)
class Wisp(var x: Double, var y: Double, var stunnedTicks: Int)
val realmNames = Array("THE FORGOTTEN VILLAGE", "WHISPERING BLACKWOOD", "THE ETERNAL CITADEL")
val realmSubtitles = Array("Find the lost village moon sigils", "Follow the lanterns through the cursed forest", "Face the Warden and open the final gate")
val realmColors = Array(new Color(67, 83, 130), new Color(72, 46, 112), new Color(112, 52, 105))
val keys = scala.collection.mutable.Set[Int]()
val wisps = ArrayBuffer[Wisp]()
var sigils = ArrayBuffer[Sigil]()
var realm = 0
var playerX = 95.0
var playerY = 380.0
var playerLives = 3
var score = 0
var totalSigils = 0
var curseMeter = 0.0
var paused = false
var gameOver = false
var victory = false
var tick = 0
var dashTicks = 0
var dashCooldown = 0
var pulseCooldown = 0
var auraTicks = 0
var auraCooldown = 0
var invulnerableTicks = 0
var message = "Find 4 Moon Sigils to unlock the realm gate."
var mouseTargetX = -1.0
var mouseTargetY = -1.0
var bossHealth = 3
var bossStunnedTicks = 0
var bossX = 785.0
var bossY = 355.0
var bossDefeated = false
var gameTimer: Timer = null
loadRealm()
def startGame(): Unit = {
if (gameTimer == null) {
gameTimer = new Timer(25, new ActionListener {
def actionPerformed(e: ActionEvent): Unit = updateGame()
})
gameTimer.start()
}
requestFocusInWindow()
}
def stopGame(): Unit = {
if (gameTimer != null) gameTimer.stop()
}
def loadRealm(): Unit = {
playerX = 95.0
playerY = 380.0
mouseTargetX = -1.0
mouseTargetY = -1.0
sigils.clear()
sigils += new Sigil(235, 210, false)
sigils += new Sigil(405, 500, false)
sigils += new Sigil(590, 220, false)
sigils += new Sigil(735, 505, false)
wisps.clear()
wisps += new Wisp(370.0, 330.0, 0)
wisps += new Wisp(650.0, 420.0, 0)
if (realm > 0) wisps += new Wisp(520.0, 545.0, 0)
bossHealth = 3
bossStunnedTicks = 0
bossX = 785.0
bossY = 355.0
bossDefeated = false
curseMeter = 0.0
message = realmSubtitles(realm)
}
def currentSigils(): Int = sigils.count(s => s.collected)
def updateGame(): Unit = {
if (paused || gameOver || victory) {
repaint()
return
}
tick += 1
if (dashTicks > 0) dashTicks -= 1
if (dashCooldown > 0) dashCooldown -= 1
if (pulseCooldown > 0) pulseCooldown -= 1
if (auraTicks > 0) auraTicks -= 1
if (auraCooldown > 0) auraCooldown -= 1
if (invulnerableTicks > 0) invulnerableTicks -= 1
if (bossStunnedTicks > 0) bossStunnedTicks -= 1
val baseSpeed = 2.35 + Math.min(0.9, totalSigils * 0.045)
val speed = if (dashTicks > 0) baseSpeed * 2.8 else baseSpeed
var dx = 0.0
var dy = 0.0
if (keys.contains(KeyEvent.VK_A) || keys.contains(KeyEvent.VK_LEFT)) dx -= 1.0
if (keys.contains(KeyEvent.VK_D) || keys.contains(KeyEvent.VK_RIGHT)) dx += 1.0
if (keys.contains(KeyEvent.VK_W) || keys.contains(KeyEvent.VK_UP)) dy -= 1.0
if (keys.contains(KeyEvent.VK_S) || keys.contains(KeyEvent.VK_DOWN)) dy += 1.0
if (dx != 0.0 || dy != 0.0) {
val length = Math.sqrt(dx * dx + dy * dy)
playerX += (dx / length) * speed
playerY += (dy / length) * speed
mouseTargetX = -1.0
mouseTargetY = -1.0
} else if (mouseTargetX >= 0.0) {
val tx = mouseTargetX - playerX
val ty = mouseTargetY - playerY
val distance = Math.sqrt(tx * tx + ty * ty)
if (distance < 6.0) {
mouseTargetX = -1.0
mouseTargetY = -1.0
} else {
playerX += tx / distance * speed
playerY += ty / distance * speed
}
}
playerX = Math.max(55.0, Math.min(905.0, playerX))
playerY = Math.max(145.0, Math.min(625.0, playerY))
sigils.foreach { s =>
if (!s.collected && distance(playerX, playerY, s.x, s.y) < 27.0) {
s.collected = true
totalSigils += 1
score += 150
curseMeter = Math.max(0.0, curseMeter - 12.0)
message = "Moon Sigil collected! Your light grows stronger."
}
}
wisps.foreach { w =>
if (w.stunnedTicks > 0) w.stunnedTicks -= 1
else {
val vx = playerX - w.x
val vy = playerY - w.y
val d = Math.sqrt(vx * vx + vy * vy)
if (d > 1.0) {
val wispSpeed = 0.58 + realm * 0.12
w.x += vx / d * wispSpeed
w.y += vy / d * wispSpeed
}
if (d < 25.0 && invulnerableTicks == 0 && auraTicks == 0) {
playerLives -= 1
curseMeter = Math.min(100.0, curseMeter + 18.0)
invulnerableTicks = 95
playerX = 95.0
playerY = 380.0
message = "A Shadow Wisp touched you! Return to the lantern path."
if (playerLives <= 0) gameOver = true
}
}
}
if (realm == 2 && currentSigils() >= 4 && !bossDefeated) {
if (bossStunnedTicks == 0) {
val vx = playerX - bossX
val vy = playerY - bossY
val d = Math.sqrt(vx * vx + vy * vy)
if (d > 1.0) {
bossX += vx / d * 0.72
bossY += vy / d * 0.72
}
if (d < 33.0 && invulnerableTicks == 0 && auraTicks == 0) {
playerLives -= 1
invulnerableTicks = 105
curseMeter = Math.min(100.0, curseMeter + 25.0)
playerX = 95.0
playerY = 380.0
message = "The Eternal Warden pushed you back! Use Lantern Pulse."
if (playerLives <= 0) gameOver = true
}
}
}
curseMeter = Math.min(100.0, curseMeter + 0.018)
if (curseMeter >= 100.0) {
curseMeter = 45.0
if (invulnerableTicks == 0) {
playerLives -= 1
invulnerableTicks = 90
playerX = 95.0
playerY = 380.0
message = "Eternal Curse surge! The lantern sent you back to Base."
if (playerLives <= 0) gameOver = true
}
}
repaint()
}
def distance(x1: Double, y1: Double, x2: Double, y2: Double): Double = {
val dx = x1 - x2
val dy = y1 - y2
Math.sqrt(dx * dx + dy * dy)
}
def activateDash(): Unit = {
if (!paused && dashCooldown == 0 && !gameOver && !victory) {
dashTicks = 9
dashCooldown = 65
message = "Moon Dash activated!"
}
}
def lanternPulse(): Unit = {
if (!paused && pulseCooldown == 0 && !gameOver && !victory) {
pulseCooldown = 78
wisps.foreach { w =>
if (distance(playerX, playerY, w.x, w.y) < 190.0) w.stunnedTicks = 110
}
if (realm == 2 && currentSigils() >= 4 && !bossDefeated && distance(playerX, playerY, bossX, bossY) < 205.0) {
bossHealth -= 1
bossStunnedTicks = 95
score += 250
message = "Lantern Pulse struck the Eternal Warden!"
if (bossHealth <= 0) {
bossDefeated = true
score += 1000
message = "The Eternal Warden is defeated! Reach the final Moon Gate."
}
} else {
message = "Lantern Pulse! Nearby Shadow Wisps are stunned."
}
}
}
def activateAura(): Unit = {
if (!paused && auraCooldown == 0 && !gameOver && !victory) {
auraTicks = 100
auraCooldown = 240
message = "Moon Aura protects you for a short time."
}
}
def interact(): Unit = {
if (gameOver || victory || paused) return
if (distance(playerX, playerY, 95.0, 380.0) < 72.0) {
curseMeter = Math.max(0.0, curseMeter - 8.0)
message = "Safe at Lantern Base. The curse is fading."
return
}
if (currentSigils() < 4) {
message = "The Moon Gate is sealed. Collect all 4 Moon Sigils first."
return
}
if (realm == 2 && !bossDefeated) {
message = "The Eternal Warden guards the final gate. Use F near it!"
return
}
if (distance(playerX, playerY, 865.0, 380.0) < 85.0) {
if (realm < 2) {
realm += 1
loadRealm()
} else {
victory = true
message = "The Eternal Curse has been broken!"
}
} else {
message = "Find the glowing Moon Gate on the right side of the realm."
}
}
def returnToBase(): Unit = {
playerX = 95.0
playerY = 380.0
mouseTargetX = -1.0
mouseTargetY = -1.0
curseMeter = Math.max(0.0, curseMeter - 16.0)
message = "Returned to Lantern Base."
}
def restartGame(): Unit = {
realm = 0
playerLives = 3
score = 0
totalSigils = 0
curseMeter = 0.0
paused = false
gameOver = false
victory = false
tick = 0
dashCooldown = 0
pulseCooldown = 0
auraCooldown = 0
invulnerableTicks = 0
loadRealm()
requestFocusInWindow()
}
addKeyListener(new KeyAdapter {
override def keyPressed(e: KeyEvent): Unit = {
val code = e.getKeyCode
if (!keys.contains(code)) {
if (code == KeyEvent.VK_SPACE) activateDash()
if (code == KeyEvent.VK_F) lanternPulse()
if (code == KeyEvent.VK_Q) activateAura()
if (code == KeyEvent.VK_E) interact()
if (code == KeyEvent.VK_B) returnToBase()
if (code == KeyEvent.VK_P) paused = !paused
if (code == KeyEvent.VK_R && (gameOver || victory)) restartGame()
}
keys += code
}
override def keyReleased(e: KeyEvent): Unit = keys -= e.getKeyCode
})
addMouseListener(new MouseAdapter {
override def mousePressed(e: MouseEvent): Unit = {
requestFocusInWindow()
if (!paused && !gameOver && !victory && e.getY > 115) {
mouseTargetX = e.getX.toDouble
mouseTargetY = e.getY.toDouble
}
}
})
def drawText(g: Graphics2D, text: String, x: Int, y: Int, size: Int, color: Color): Unit = {
g.setFont(new Font("SansSerif", Font.BOLD, size))
g.setColor(color)
g.drawString(text, x, y)
}
override def paintComponent(graphics: Graphics): Unit = {
super.paintComponent(graphics)
val g = graphics.asInstanceOf[Graphics2D]
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
val sky = realmColors(realm)
g.setPaint(new GradientPaint(0, 0, new Color(9, 8, 22), 0, getHeight, sky.darker().darker()))
g.fillRect(0, 0, getWidth, getHeight)
var i = 0
while (i < 90) {
val sx = (i * 137 + 29) % 960
val sy = (i * 79 + 17) % 680
g.setColor(new Color(210, 198, 255, 90))
g.fillOval(sx, sy, 2, 2)
i += 1
}
g.setColor(new Color(176, 157, 221, 45))
g.fillOval(695, 55, 170, 170)
g.setColor(new Color(26, 19, 43))
g.fillOval(735, 42, 170, 170)
g.setColor(new Color(10, 9, 22, 190))
g.fillRect(0, 0, 960, 112)
drawText(g, "SHADOWFALL: ETERNAL CURSE", 24, 36, 23, new Color(232, 220, 255))
drawText(g, playerName + " | " + realmNames(realm), 25, 67, 14, new Color(190, 173, 226))
drawText(g, "SCORE " + score + " SIGILS " + totalSigils + "/12 LIVES " + playerLives, 25, 94, 13, new Color(238, 218, 176))
// Haunted landscape and silhouettes
g.setColor(new Color(11, 10, 25, 175))
g.fillOval(-90, 470, 360, 210)
g.fillOval(200, 495, 360, 190)
g.fillOval(550, 465, 490, 220)
var tree = 0
while (tree < 8) {
val tx = 160 + tree * 105
g.setColor(new Color(17, 13, 31))
g.fillRect(tx, 300 + (tree % 3) * 26, 13, 245)
g.fillOval(tx - 48, 255 + (tree % 2) * 38, 110, 100)
tree += 1
}
// Lantern Base
g.setColor(new Color(40, 28, 63))
g.fillRoundRect(48, 340, 95, 80, 18, 18)
g.setColor(new Color(241, 201, 122))
g.setStroke(new BasicStroke(3.0f))
g.drawRoundRect(48, 340, 95, 80, 18, 18)
g.fillOval(82, 365, 27, 27)
drawText(g, "BASE", 69, 438, 12, new Color(246, 220, 166))
// Sigils
sigils.foreach { s =>
if (!s.collected) {
g.setColor(new Color(184, 157, 255, 55))
g.fillOval(s.x - 23, s.y - 23, 46, 46)
g.setColor(new Color(222, 205, 255))
val px = Array(s.x, s.x + 13, s.x, s.x - 13)
val py = Array(s.y - 18, s.y, s.y + 18, s.y)
g.fillPolygon(px, py, 4)
g.setColor(new Color(255, 239, 196))
g.fillOval(s.x - 4, s.y - 4, 8, 8)
}
}
// Moon Gate
val gateOpen = currentSigils() >= 4 && (realm < 2 || bossDefeated)
g.setColor(new Color(148, 105, 210, 55))
g.fillOval(820, 295, 90, 165)
g.setStroke(new BasicStroke(8.0f))
g.setColor(if (gateOpen) new Color(181, 235, 205) else new Color(113, 92, 145))
g.drawOval(835, 305, 62, 140)
drawText(g, "MOON GATE", 816, 470, 11, new Color(218, 207, 240))
// Shadow Wisps
wisps.foreach { w =>
val alpha = if (w.stunnedTicks > 0) 100 else 220
g.setColor(new Color(151, 113, 205, alpha))
g.fillOval(w.x.toInt - 17, w.y.toInt - 17, 34, 34)
g.setColor(new Color(226, 216, 255, alpha))
g.fillOval(w.x.toInt - 8, w.y.toInt - 6, 5, 6)
g.fillOval(w.x.toInt + 4, w.y.toInt - 6, 5, 6)
if (w.stunnedTicks > 0) drawText(g, "Z", w.x.toInt + 12, w.y.toInt - 18, 12, Color.WHITE)
}
// Eternal Warden in the final realm
if (realm == 2 && currentSigils() >= 4 && !bossDefeated) {
g.setColor(new Color(170, 66, 120, 65))
g.fillOval(bossX.toInt - 42, bossY.toInt - 42, 84, 84)
g.setColor(new Color(85, 45, 105))
g.fillOval(bossX.toInt - 28, bossY.toInt - 34, 56, 68)
g.setColor(new Color(255, 205, 155))
g.fillOval(bossX.toInt - 13, bossY.toInt - 9, 7, 7)
g.fillOval(bossX.toInt + 7, bossY.toInt - 9, 7, 7)
drawText(g, "WARDEN " + bossHealth + "/3", bossX.toInt - 36, bossY.toInt - 42, 12, new Color(255, 215, 220))
}
// Player
if (invulnerableTicks == 0 || (tick / 5) % 2 == 0) {
if (auraTicks > 0) {
g.setColor(new Color(255, 226, 155, 75))
g.fillOval(playerX.toInt - 27, playerY.toInt - 27, 54, 54)
g.setColor(new Color(255, 229, 169))
g.drawOval(playerX.toInt - 27, playerY.toInt - 27, 54, 54)
}
g.setColor(new Color(204, 185, 244))
g.fillOval(playerX.toInt - 12, playerY.toInt - 17, 24, 24)
g.setColor(new Color(66, 49, 101))
g.fillRoundRect(playerX.toInt - 13, playerY.toInt - 2, 26, 29, 10, 10)
g.setColor(new Color(246, 218, 168))
g.fillOval(playerX.toInt - 4, playerY.toInt - 9, 3, 3)
g.fillOval(playerX.toInt + 3, playerY.toInt - 9, 3, 3)
}
// Curse meter and status
g.setColor(new Color(28, 21, 43))
g.fillRoundRect(650, 18, 280, 18, 9, 9)
g.setColor(if (curseMeter < 55.0) new Color(150, 105, 202) else new Color(223, 105, 132))
g.fillRoundRect(650, 18, (curseMeter * 2.8).toInt, 18, 9, 9)
drawText(g, "ETERNAL CURSE", 650, 53, 12, new Color(217, 204, 235))
drawText(g, "DASH " + (if (dashCooldown == 0) "READY" else "..."), 650, 75, 11, new Color(205, 190, 230))
drawText(g, "PULSE " + (if (pulseCooldown == 0) "READY" else "..."), 785, 75, 11, new Color(205, 190, 230))
g.setColor(new Color(8, 7, 18, 210))
g.fillRoundRect(170, 625, 620, 38, 12, 12)
drawText(g, message, 185, 649, 13, new Color(235, 220, 255))
drawText(g, "WASD/ARROWS MOVE | SPACE DASH | F LANTERN PULSE | Q AURA | E GATE | B BASE | P PAUSE", 70, 602, 11, new Color(201, 190, 220))
if (paused || gameOver || victory) {
g.setColor(new Color(5, 4, 13, 210))
g.fillRect(0, 0, getWidth, getHeight)
if (paused) {
drawText(g, "PAUSED", 390, 300, 42, Color.WHITE)
drawText(g, "Press P to continue", 370, 345, 18, new Color(208, 195, 235))
} else if (gameOver) {
drawText(g, "THE CURSE HAS WON", 270, 285, 36, new Color(241, 194, 215))
drawText(g, "Press R to restart the expedition", 300, 335, 18, Color.WHITE)
} else {
drawText(g, "ETERNAL CURSE BROKEN!", 245, 285, 36, new Color(225, 221, 255))
drawText(g, "All realms are free. Score: " + score, 340, 335, 18, Color.WHITE)
drawText(g, "Press R to play again", 365, 370, 16, new Color(206, 195, 235))
}
}
}
}
// Start the game when the complete Kojo script is run.
ShadowfallEternalCurseEvent8.main(Array[String]())