Code Sketch
yadnesh
// --- ISRO ULTIMATE MISSION: ROBOT SELECTION & ASTRONAUT CONTROLS EDITION ---
cleari(); originBottomLeft();
// MIDI Safe Initialization
var isGameAudioAllowed = false
try {
setNoteInstrument(Instrument.PIANO)
isGameAudioAllowed = true
} catch {
case e: Exception => println("Audio/MIDI not supported on this device.")
}
def playSoundFx(p: Int, d: Int): Unit = {
if (isGameAudioAllowed) {
try { playNote(p, d) } catch { case _: Exception => }
}
}
// Sound Tunes & Text
var fullJanaGanaTune = ArrayBuffer((53,300),(55,300),(57,300),(57,300),(57,300),(57,300),(57,300),(55,300),(57,300),(58,300),(57,300),(55,300),(53,300),(55,300),(53,500),(60,300),(60,300),(60,300),(58,300),(60,300),(58,300),(57,300),(55,300),(57,300),(58,500),(57,300),(55,300),(53,500),(53,300),(55,300),(57,300),(57,300),(57,300),(57,300),(57,300),(55,300),(57,300),(58,300),(57,300),(55,300),(53,300),(55,300),(53,500),(60,300),(60,300),(60,300),(58,300),(60,300),(58,300),(57,300),(55,300),(57,300),(58,500),(57,300),(55,300),(53,500))
val fullVandeMataramTune = Array((60,400),(62,400),(65,500),(62,400),(60,400),(62,500),(60,400),(62,400),(65,400),(67,400),(69,600),(69,400),(70,400),(69,400),(67,400),(65,400),(67,500),(65,400),(62,400),(60,400),(62,400),(60,600))
var (janaIndex, vandeIndex, charIndex, textDelayTimer) = (0, 0, 0, 0.0)
var (janaGanaFinished, anthemFinished, startAnthemPhase) = (false, false, false)
val fullAnthemText = "Jana-gana-mana-adhinayaka jaya he\nBharata-bhagya-vidhata.\nPunjaba-Sindhu-Gujarata-Maratha\nDravida-Utkala-Banga\nVindhya-Himachala-Yamuna-Ganga\nUchchhala-Jaladhi-taranga\nTava subha name jage, Tava subha asisa mage,\nGaye tava jaya gatha.\nJana-gana-mangala-dayaka jaya he\nBharata-bhagya-vidhata.\nJaya he, jaya he, jaya he,\nJaya jaya jaya, jaya he!\n\n--- VANDE MATARAM ---\nVande Mataram! Sujalam Suphalam\nMalayaja Shytamalam Shasya Shyamalam\nMataram! Vande Mataram!"
// --- STORY STAGES ---
var currentStoryStage = -2
var selectedRobotType = 1
var isRobotUnlocked = false
var robotChallengeScore = 0
var robotChallengeTarget = 5
var (robotGamePlayerX, robotGamePlayerY) = (cwidth / 2.0, 80.0)
var (cyberEnergyX, cyberEnergyY) = (cwidth / 2.0, cheight - 150.0)
var cyberEnergyVy = -3.5
// NEW: Control Room Under Rocket View State Variable
var isInsideUnderRocketControl = false
var welcomeTimer = 0.0
var letterTextTyped = 0
var letterTimer = 0.0
var titleCardTimer = 0.0
val officialLetterText =
"CONFIDENTIAL: INDIAN SPACE RESEARCH ORGANISATION (ISRO)\n" +
"SUBJECT: SELECTION FOR GAGANYAAN HUMAN SPACEFLIGHT PROGRAM\n\n" +
"Dear Commander / Candidate,\n\n" +
"Congratulations! Based on your extraordinary skill, technical excellence,\n" +
"and courage, you have been selected for India's prestigious Space Mission.\n\n" +
"Your presence is immediately requested at SDSC SHAR, Sriharikota.\n" +
"You are summoned to pilot our advanced spacecraft and represent the nation.\n\n" +
"Click below or Press 'ACCEPTED' to report to HQ and start your mission."
def playAnthemStep(): Unit = {
textDelayTimer += 0.04
if (textDelayTimer >= 0.15) { textDelayTimer = 0.0; if (charIndex < fullAnthemText.length) charIndex += 1 }
if (!janaGanaFinished) {
if (janaIndex < fullJanaGanaTune.length) { val (n, d) = fullJanaGanaTune(janaIndex); playSoundFx(n, d); janaIndex += 1 }
else { fullJanaGanaTune.clear(); janaGanaFinished = true }
} else {
if (vandeIndex < fullVandeMataramTune.length) { val (n, d) = fullVandeMataramTune(vandeIndex); playSoundFx(n, d); vandeIndex += 1 }
else if (charIndex >= fullAnthemText.length) anthemFinished = true
}
}
case class PlanetDetail(name: String, realName: String, surfaceCol: Color, darkSurfCol: Color, accent3D: Color, hasRings: Boolean, gameModeType: Int, infoLine1: String, infoLine2: String, infoLine3: String, infoLine4: String, infoLine5: String, infoLine6: String, infoLine7: String, infoLine8: String, quizQuestion: String, quizOptions: Array[String], correctOpt: Int)
val realSolarSystemMap = Array(
PlanetDetail("Mercury", "Mercury (Budh)", cm.rgb(120,120,120), cm.rgb(60,60,60), cm.rgb(200,200,200), false, 2, " Gravity: 3.7 m/s� | Closest Planet to Sun", " Extreme Temp: Very hot days, freezing nights", " High Orbital Inclination & Delta-V Criteria", " Distance: 57.9 Million km | Orbit: 88 Days", " Radius: 2,439.7 km (~2.44 Million m)", " Mass: 3.301 � 10�� kg | Temp: -180�C to 430�C", " Exosphere: Thin helium & sodium trace", " Surface: Heavily cratered silicate crust", "Which planet is closest to the Sun in our Solar System?", Array("Mercury", "Venus", "Mars", "Earth"), 0),
PlanetDetail("Venus", "Venus (Shukra)", cm.rgb(210,150,80), cm.rgb(100,70,30), cm.rgb(255,200,130), false, 3, " Gravity: 8.87 m/s� | Shukrayaan-1 Target", " Dense Atmosphere: 96.5% Carbon Dioxide", " High-Resolution Synthetic Aperture Radar", " Distance: 108.2 Million km | Orbit: 225 Days", " Radius: 6,051.8 km (~6.05 Million m)", " Mass: 4.867 � 10�? kg | Temp: ~464�C", " Pressure: 92 bar (Supercritical CO2)", " Clouds: Concentrated sulfuric acid droplets", "Which is the hottest planet in the Solar System?", Array("Venus", "Mercury", "Mars", "Jupiter"), 0),
PlanetDetail("Earth", "Earth (Prithvi)", cm.rgb(40,130,240), cm.rgb(20,60,120), cm.rgb(100,200,255), false, 1, " Gravity: 9.81 m/s� | Our Home Planet", " Satellite: Moon (Chandrayaan-3 South Pole)", " Launch Centre: SDSC SHAR, Sriharikota", " Distance: 149.6 Million km (1 AU)", " Radius: 6,371 km (~6.37 Million m)", " Mass: 5.972 � 10�? kg | Temp: -89�C to 58�C", " Atmosphere: 78% Nitrogen, 21% Oxygen", " Biosphere: Only known life-bearing world", "How many days does Earth take to complete one orbit around the Sun?", Array("365 Days", "100 Days", "500 Days", "30 Days"), 0),
PlanetDetail("Mars", "Mars (Mangal)", cm.rgb(200,70,40), cm.rgb(100,30,15), cm.rgb(255,130,100), false, 2, " Gravity: 3.72 m/s� | Mars Orbiter Mission (MOM)", " Launch Vehicle: PSLV-XL C25 Config", " Interplanetary Hohmann Transfer Orbit", " Distance: 227.9 Million km | Orbit: 687 Days", " Radius: 3,389.5 km (~3.39 Million m)", " Mass: 6.417 � 10�� kg | Temp: -125�C to 20�C", " Thin Atmosphere: 95% CO2, low pressure", " Topography: Olympus Mons & Valles Marineris", "Which planet is famously known as the 'Red Planet'?", Array("Mars", "Mercury", "Jupiter", "Saturn"), 0),
PlanetDetail("Jupiter", "Jupiter (Guru)", cm.rgb(210,140,90), cm.rgb(100,60,40), cm.rgb(255,190,140), true, 1, " Gravity: 24.79 m/s� | Largest Planet", " Powerful Magnetic Field & Radiation", " Subsurface Water Ocean on Europa", " Distance: 778.5 Million km | Orbit: 11.8 Years", " Radius: 69,911 km (~69.9 Million m)", " Mass: 1.898 � 10�? kg | Temp: ~ -110�C", " Composition: 90% Hydrogen, 10% Helium", " Great Red Spot: Giant anticyclonic storm", "Which is the largest planet in our Solar System?", Array("Jupiter", "Saturn", "Neptune", "Earth"), 0),
PlanetDetail("Saturn", "Saturn (Shani)", cm.rgb(190,170,110), cm.rgb(90,80,50), cm.rgb(240,230,160), true, 2, " Gravity: 10.44 m/s� | Ringed Planet Jewel", " Titan's Dense Atmosphere & Hydrocarbons", " Active Cryovolcanism on Enceladus", " Distance: 1.4 Billion km | Orbit: 29.5 Years", " Radius: 58,232 km (~58.2 Million m)", " Mass: 5.683 � 10�? kg | Temp: ~ -140�C", " Rings: 99% water ice with silicate dust", " Density: Less than water (0.687 g/cm�)", "Which planet is famous for its bright prominent ring system?", Array("Saturn", "Mars", "Mercury", "Venus"), 0),
PlanetDetail("Uranus", "Uranus (Arun)", cm.rgb(100,200,220), cm.rgb(40,90,100), cm.rgb(180,240,255), true, 3, " Gravity: 8.69 m/s� | Extreme 97.77� Tilt", " Ice Giant with Methane Mantle Overlay", " Off-center Offset Magnetic Axis", " Distance: 2.87 Billion km | Orbit: 84 Years", " Radius: 25,362 km (~25.3 Million m)", " Mass: 8.681 � 10�? kg | Temp: ~ -195�C", " Atmosphere: Hydrogen, helium, methane ice", " Coldest Planetary Atmosphere in Solar System", "Which blue-green ice giant planet has an extreme axial tilt?", Array("Uranus", "Mars", "Venus", "Mercury"), 0),
PlanetDetail("Neptune", "Neptune (Varun)", cm.rgb(50,90,220), cm.rgb(20,40,100), cm.rgb(130,170,255), true, 2, " Gravity: 11.15 m/s� | Outermost Major Planet", " Supersonic Winds: Up to 2,100 km/h", " Retrograde Orbit of Triton Moon", " Distance: 4.5 Billion km | Orbit: 165 Years", " Radius: 24,622 km (~24.6 Million m)", " Mass: 1.024 � 10�? kg | Temp: ~ -200�C", " Dynamic Atmosphere: Great Dark Spot storms", " Triton: Active nitrogen geysers observed", "Which is the farthest major planet from the Sun in our Solar System?", Array("Neptune", "Mars", "Jupiter", "Mercury"), 0)
)
val keplerSolarSystemMap = Array(
PlanetDetail("Kepler-22b", "Kepler-22b (KOI-087.01)", cm.rgb(70,180,150), cm.rgb(30,90,70), cm.rgb(120,240,200), false, 2, " First habitable 'Super-Earth' planet candidate.", " Size: 2.4 times larger than Earth.", " Orbital Distance: 0.85 AU (127 Million km)", " Distance from Earth: ~635 Light Years", " Radius: ~15,290 km (~15.29 Million m)", " Mass: ~9.1 Earth Masses | Temp: -11�C to 22�C", " Planet Type: Potential Ocean World or Mini-Neptune", " Discovery Year: 2011 (Kepler Telescope)", "Because Kepler-22b is larger than Earth, what classification is it given?", Array("Super-Earth", "Mini-Moon", "Small Star", "Flat World"), 0),
PlanetDetail("Kepler-16b", "Kepler-16b (Kepler-16AB b)", cm.rgb(200,160,220), cm.rgb(90,70,110), cm.rgb(245,210,255), true, 3, " Famous 'Tatooine' planet with dual suns.", " Orbits around two stars simultaneously (Circumbinary).", " Gas Giant composition (Saturn-sized).", " Distance from Earth: ~245 Light Years", " Radius: ~53,200 km (~53.2 Million m)", " Mass: ~0.33 Jupiter Mass | Temp: -70�C", " Primary Stars: K-dwarf + M-dwarf pair", " Orbit Period: 229 Days around binary center", "How many host stars does planet Kepler-16b orbit?", Array("2 Stars (Binary)", "1 Star", "5 Stars", "None"), 0),
PlanetDetail("Kepler-186f", "Kepler-186f (KOI-571.05)", cm.rgb(140,210,110), cm.rgb(60,90,45), cm.rgb(200,255,170), false, 2, " First Earth-sized planet in Habitable Zone.", " Potential candidate for liquid surface water.", " High probability of rocky surface terrain.", " Distance from Earth: ~580 Light Years", " Radius: ~7,450 km (~7.45 Million m)", " Mass: ~1.4 Earth Mass | Orbit: 130 Days", " Host Star: Red Dwarf (M1V class)", " Insolation: Receives 32% of Earth's sunlight", "Is planet Kepler-186f located in its star's Habitable Zone?", Array("Yes", "No", "Unknown", "Never"), 0),
PlanetDetail("Kepler-452b", "Kepler-452b (KOI-7016.01)", cm.rgb(90,140,200), cm.rgb(40,70,110), cm.rgb(160,210,255), false, 1, " Famously known as 'Earth's Cousin' (Earth 2.0).", " Orbital year length: 385 Days (Near Earth twin).", " Super-Earth Class rocky/thick atmosphere planet.", " Distance from Earth: ~1,800 Light Years", " Radius: ~10,380 km (~10.38 Million m)", " Mass: ~5 Earth Masses | Temp: ~ -8�C", " Host Star: Kepler-452 (G2V Solar Twin)", " Age: ~6 Billion Years (1.5B years older than Sun)", "What nickname was given to Kepler-452b due to its Earth-like traits?", Array("Earth's Cousin", "Moon Twin", "Sun Twin", "Mars Twin"), 0),
PlanetDetail("Kepler-10b", "Kepler-10b (KOI-072.01)", cm.rgb(220,90,90), cm.rgb(110,40,40), cm.rgb(255,160,160), false, 3, " Extreme 'Lava World' with molten surface.", " Very close proximity to host star.", " Surface temp churns rock/lava (>1,300�C).", " Distance from Earth: ~560 Light Years", " Radius: ~9,360 km (~9.36 Million m)", " Mass: ~3.2 Earth Masses | Orbit: 20 Hours", " Tidal Locking: One side permanently molten", " Density: High silicate and iron core", "What covers the surface of Kepler-10b due to extreme heat?", Array("Molten Lava / Rock", "Ice Mountains", "Cold Water", "Green Forests"), 0),
PlanetDetail("Kepler-62f", "Kepler-62f (KOI-701.04)", cm.rgb(80,190,210), cm.rgb(35,90,100), cm.rgb(150,245,255), false, 1, " Candidate 'Ocean World' covered by global sea.", " Approximately 40% larger than Earth.", " Host Star: K-type Orange Dwarf.", " Distance from Earth: ~1,200 Light Years", " Radius: ~8,980 km (~8.98 Million m)", " Mass: ~2.8 Earth Masses | Orbit: 267 Days", " Climate Model: Stable global ocean with greenhouse gas", " Habitable Index: Very High", "What is Kepler-62f most likely covered by?", Array("A Global Ocean", "Only Sand Deserts", "Gas Only", "Plastic"), 0),
PlanetDetail("Kepler-90i", "Kepler-90i (KOI-351 i)", cm.rgb(230,150,60), cm.rgb(110,70,20), cm.rgb(255,210,130), false, 2, " Part of 8-planet system found by Google AI.", " Discovered via Neural Network Machine Learning.", " Sizzling rocky terrestrial surface.", " Distance from Earth: ~2,840 Light Years", " Radius: ~8,410 km (~8.41 Million m)", " Mass: ~2.5 Earth Masses | Orbit: 14.4 Days", " System Structure: Matches Solar System planet count", " Surface Temp: ~430�C", "Which technology helped discover planet Kepler-90i?", Array("Artificial Intelligence (Google AI)", "Simple Camera", "Microscope", "Newspaper"), 0),
PlanetDetail("K2-18b", "K2-18b (EPIC 201912552 b)", cm.rgb(60,200,180), cm.rgb(20,90,80), cm.rgb(140,255,235), false, 2, " Hycean Planet with hydrogen atmosphere.", " JWST detected water vapor & methane traces.", " Potential liquid ocean beneath atmosphere.", " Distance from Earth: ~124 Light Years", " Radius: ~16,620 km (~16.62 Million m)", " Mass: ~8.6 Earth Masses | Temp: ~ -8�C", " JWST Detection: Carbon-bearing molecules (CO2, CH4)", " Potential Biosignature: DMS trace research", "What trace evidence did the Space Telescope find in K2-18b's atmosphere?", Array("Water Vapor", "Petrol", "Diesel", "Milk"), 0)
)
val starCount = 850
val starX = Array.fill(starCount)(randomDouble(0, cwidth))
val starY = Array.fill(starCount)(randomDouble(0, cheight))
val starSize = Array.fill(starCount)(randomDouble(1.0, 4.2))
var (waveAngle, chakraRotation, neonGlowPhase, globalTime) = (0.0, 0.0, 0.0, 0.0)
var currentSolarSystemId = 1
var (rotAngleX, rotAngleY) = (0.45, 0.0)
var (lastMouseX, lastMouseY) = (0.0, 0.0)
var isDraggingSolarView = false
def getActivePlanetList(): Array[String] = if (currentSolarSystemId == 1) Array("Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune") else Array("Kepler-22b", "Kepler-16b", "Kepler-186f", "Kepler-452b", "Kepler-10b", "Kepler-62f", "Kepler-90i", "K2-18b")
def getActivePlanetDetailsMap(): Array[PlanetDetail] = if (currentSolarSystemId == 1) realSolarSystemMap else keplerSolarSystemMap
var selectedPlanet = "Mars"
var (planetLocked, isTimerRunning, isSpaceTravelling, isLandingOnPlanet, isLaunched, isLanded) = (false, false, false, false, false, false)
var (customAlertMessage, quizFeedback) = ("", "")
var (alertTimer, countdownTimer, spaceTravelProgress, landingProgress, doorOpeningProgress, astroWaitTimer, flagPlantProgress, landingLegProgress) = (0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
var (rocketCurrentX, rocketCurrentY) = (90.0, cheight - 170.0)
var (astronautOut, infoPanelShown, isFlagPlantedOnPlanet, isAstronautReturningIn, quizActive, isMiniGameActive, readyToReturnEarth) = (false, false, false, false, false, false, false)
var (infoPageNumber, activeGameMode) = (1, 1)
var astroWalkToPlantX = 0.0
val plantedFlagX = (cwidth / 2.0) - 80.0
val plantedFlagY = 155.0
case class DynamicParticle(var x: Double, var y: Double, var vx: Double, var vy: Double, var life: Double, col: Color, var size: Double)
val exhaustRibbons = ArrayBuffer.empty[DynamicParticle]
val dustParticles = ArrayBuffer.empty[DynamicParticle]
val explosionParticles = ArrayBuffer.empty[DynamicParticle]
val petalShower = ArrayBuffer.fill(50)(DynamicParticle(randomDouble(0, cwidth), randomDouble(cheight, cheight + 200), randomDouble(-0.6, 0.6), randomDouble(-2.2, -1.0), 1.0, cm.rgb(255, 153, 51), randomDouble(4, 8)))
def addTricolorExhaust(x: Double, y: Double): Unit = {
val t = globalTime * 14.0
exhaustRibbons.append(DynamicParticle(x - 8 + math.sin(t) * 6, y, randomDouble(-1.2, 1.2), randomDouble(-4.0, -2.0), 1.0, cm.rgb(255, 153, 51), randomDouble(8.0, 15.0)))
exhaustRibbons.append(DynamicParticle(x, y, randomDouble(-0.8, 0.8), randomDouble(-5.0, -3.0), 1.0, cm.rgb(255, 255, 255), randomDouble(10.0, 17.0)))
exhaustRibbons.append(DynamicParticle(x + 8 + math.cos(t) * 6, y, randomDouble(-1.2, 1.2), randomDouble(-4.0, -2.0), 1.0, cm.rgb(18, 136, 7), randomDouble(8.0, 15.0)))
}
def addLandingDust(x: Double, y: Double): Unit = {
for (_ <- 0 until 5) dustParticles.append(DynamicParticle(x + randomDouble(-35, 35), y, randomDouble(-2.8, 2.8), randomDouble(0.2, 1.8), 1.0, cm.rgb(210, 180, 140), randomDouble(4.0, 10.0)))
}
def triggerExplosion(x: Double, y: Double): Unit = {
for (_ <- 0 until 30) {
val gVal = randomDouble(50, 200).toInt
explosionParticles.append(DynamicParticle(x, y, randomDouble(-7.0, 7.0), randomDouble(-7.0, 7.0), 1.0, cm.rgb(255, gVal, 0), randomDouble(5.0, 14.0)))
}
}
def updateExhaust(): Unit = {
exhaustRibbons.filterInPlace(_.life > 0)
exhaustRibbons.foreach { p => p.x += p.vx + math.sin(globalTime * 10.0) * 1.5; p.y += p.vy; p.life -= 0.035; p.size += 0.4 }
dustParticles.filterInPlace(_.life > 0)
dustParticles.foreach { p => p.x += p.vx; p.y += p.vy; p.life -= 0.03; p.size += 0.25 }
explosionParticles.filterInPlace(_.life > 0)
explosionParticles.foreach { p => p.x += p.vx; p.y += p.vy; p.life -= 0.045; p.size *= 0.94 }
petalShower.foreach { p => p.y += p.vy; p.x += math.sin(globalTime * 3 + p.y * 0.05) * 1.4; if (p.y < 0) { p.y = cheight + 20; p.x = randomDouble(0, cwidth) } }
}
var miniGameTimer = 20.0
var isMiniGameTimerRunning = false
var (devilPlayerX, devilPlayerY, devilPlayerVy, devilPlayerVx) = ((cwidth / 2.0) - 180.0, 130.0, 0.0, 0.0)
var (isGrounded, canDoubleJump, jumpKeyPressedLastFrame, isDevilKeyCollected) = (false, false, false, false)
var (trollKeyX, trollKeyY, exitDoorX) = ((cwidth / 2.0) + 140.0, 140.0, (cwidth / 2.0) - 180.0)
var (dodgerShipX, dodgerShipY) = (cwidth / 2.0, cheight / 2.0 - 50.0)
val dodgerCount = 5
var dodgerAstX = Array.fill(dodgerCount)(cwidth / 2.0)
var dodgerAstY = Array.fill(dodgerCount)(cheight / 2.0 + 150.0)
var dodgerAstSpeed = Array.fill(dodgerCount)(4.0)
var dodgerScore = 0
var (landerX, landerY, landerVy, landerVx, landerFuel) = (cwidth / 2.0, cheight / 2.0 + 50.0, 0.0, 0.0, 100.0)
def resetDodgerGame(): Unit = {
val gx = cwidth / 2.0 - 220.0; dodgerShipX = cwidth / 2.0; dodgerScore = 0
for (i <- 0 until dodgerCount) { dodgerAstX(i) = gx + 30.0 + randomDouble(0, 380); dodgerAstY(i) = (cheight / 2.0 + 90.0) + (i * 40.0); dodgerAstSpeed(i) = randomDouble(3.2, 5.5) }
}
def resetLanderGame(): Unit = { landerX = cwidth / 2.0; landerY = cheight / 2.0 + 60.0; landerVy = 0.2; landerVx = 0.0; landerFuel = 100.0 }
var (isReturnTimerRunning, isReturnLaunched, isLandingOnEarth, isLandedOnEarth, isParadeSceneActive, isParadeInPosition) = (false, false, false, false, false, false)
var (returnCountdownTimer, earthLandingProgress, earthAstronautWalkRightProgress) = (5.0, 0.0, 0.0)
var (astroParadeWalkX, armyParadeWalkX) = (-50.0, cwidth + 50.0)
def dieAndResetDevilLevel(msg: String): Unit = {
playSoundFx(38, 300); triggerExplosion(devilPlayerX, devilPlayerY); customAlertMessage = s" $msg"; alertTimer = 1.8; miniGameTimer = 20.0; isMiniGameTimerRunning = true
getActivePlanetDetailsMap().foreach { pd => if (pd.name == selectedPlanet) activeGameMode = pd.gameModeType }
if (activeGameMode == 1) resetDodgerGame()
else if (activeGameMode == 3) resetLanderGame()
else {
val gx = cwidth / 2.0 - 220.0; val gy = cheight / 2.0 - 100.0
devilPlayerX = gx + 30.0; devilPlayerY = gy + 170.0; devilPlayerVy = 0.0; devilPlayerVx = 0.0; isGrounded = false; canDoubleJump = true
trollKeyX = gx + 340.0; isDevilKeyCollected = false; exitDoorX = gx + 40.0
}
}
def updateState(): Unit = {
if (currentStoryStage == -3) {
if (isKeyPressed(Kc.VK_LEFT) && robotGamePlayerX > 80.0) robotGamePlayerX -= 7.5
if (isKeyPressed(Kc.VK_RIGHT) && robotGamePlayerX < cwidth - 80.0) robotGamePlayerX += 7.5
cyberEnergyY += cyberEnergyVy
if (cyberEnergyY < 50.0) {
cyberEnergyY = cheight - 80.0
cyberEnergyX = randomDouble(100.0, cwidth - 100.0)
}
if (math.abs(robotGamePlayerX - cyberEnergyX) < 40.0 && math.abs(robotGamePlayerY - cyberEnergyY) < 40.0) {
robotChallengeScore += 1
playSoundFx(78, 120)
cyberEnergyY = cheight - 80.0
cyberEnergyX = randomDouble(100.0, cwidth - 100.0)
if (robotChallengeScore >= robotChallengeTarget) {
isRobotUnlocked = true
currentStoryStage = -1
playSoundFx(84, 350)
}
}
return
}
if (currentStoryStage == -2) return
if (currentStoryStage == -1) {
welcomeTimer += 0.04
if (welcomeTimer >= 7.5) { currentStoryStage = 0 }
return
}
if (currentStoryStage == 0) {
letterTimer += 0.04
if (letterTimer >= 0.03 && letterTextTyped < officialLetterText.length) {
letterTextTyped += 1; letterTimer = 0.0
if (letterTextTyped % 4 == 0) playSoundFx(70, 15)
}
return
}
if (currentStoryStage == 1) {
titleCardTimer += 0.03
if (titleCardTimer >= 3.0) { currentStoryStage = 2 }
return
}
if (startAnthemPhase) { waveAngle += 0.22; if (!anthemFinished) playAnthemStep(); return }
waveAngle += 0.22; chakraRotation += 0.22; neonGlowPhase += 0.22; globalTime += 0.022
updateExhaust()
if (!isLaunched && !infoPanelShown && !quizActive && !isMiniGameActive && !isInsideUnderRocketControl) {
if (isMousePressed) {
if (!isDraggingSolarView && mouseX > 240 && mouseX < cwidth - 255) { isDraggingSolarView = true; lastMouseX = mouseX; lastMouseY = mouseY }
else if (isDraggingSolarView) {
val dx = mouseX - lastMouseX; val dy = mouseY - lastMouseY
rotAngleY += dx * 0.012; rotAngleX += dy * 0.012
lastMouseX = mouseX; lastMouseY = mouseY
}
} else isDraggingSolarView = false
}
if (alertTimer > 0) { alertTimer -= 0.04; if (alertTimer <= 0) customAlertMessage = "" }
if (isTimerRunning && countdownTimer > 0) { countdownTimer -= 0.04; if (countdownTimer <= 0) { countdownTimer = 0.0; isTimerRunning = false; quizActive = true } }
if (isSpaceTravelling && !isLandingOnPlanet) {
addTricolorExhaust(rocketCurrentX, rocketCurrentY - 20); spaceTravelProgress += 0.005
var (targetX, targetY) = (cwidth / 2.0, cheight / 2.0)
val pList = getActivePlanetList(); val planetSpeeds = Array(0.6, 0.45, 0.35, 0.3, 0.25, 0.2, 0.15, 0.1)
for (i <- pList.indices if pList(i) == selectedPlanet) {
val a = globalTime * (if(i < planetSpeeds.length) planetSpeeds(i) else 0.2)
targetX = (cwidth / 2.0 - 20.0) + math.cos(a) * ((i + 1) * 28.0); targetY = (cheight / 2.0 - 10.0) + math.sin(a) * ((i + 1) * 14.0)
}
val arcOffset = math.sin(spaceTravelProgress * math.Pi) * 90.0
rocketCurrentX = (90.0 + (targetX - 90.0) * spaceTravelProgress) + arcOffset
rocketCurrentY = ((cheight - 170.0) + (targetY - (cheight - 170.0)) * spaceTravelProgress) - arcOffset
if (spaceTravelProgress >= 1.0) { isSpaceTravelling = false; isLandingOnPlanet = true; landingProgress = 0.0; landingLegProgress = 0.0; isLaunched = true; rocketCurrentX = cwidth / 2.0; rocketCurrentY = cheight + 100.0 }
}
if (isLandingOnPlanet && !isLanded) {
addTricolorExhaust(rocketCurrentX, rocketCurrentY - 25); landingProgress += 0.004
if (landingProgress > 0.4 && landingLegProgress < 1.0) landingLegProgress += 0.02
if (landingProgress > 0.8) addLandingDust(rocketCurrentX, 140.0)
rocketCurrentX = (cwidth / 2.0) + math.sin(landingProgress * math.Pi * 5) * 18.0
rocketCurrentY = (cheight + 100.0) - ((cheight + 100.0) - 175.0) * landingProgress
if (landingProgress >= 1.0) { isLandingOnPlanet = false; isLanded = true; rocketCurrentX = cwidth / 2.0; rocketCurrentY = 175.0; landingLegProgress = 1.0; playSoundFx(45, 250) }
}
if (isLanded && !isReturnLaunched && !isAstronautReturningIn && !isLandingOnEarth && !readyToReturnEarth && !infoPanelShown && !isMiniGameActive && !isInsideUnderRocketControl) {
if (doorOpeningProgress < 1.0) doorOpeningProgress += 0.01
else {
astronautOut = true
if (isKeyPressed(Kc.VK_RIGHT) && astroWalkToPlantX < 160.0) astroWalkToPlantX += 2.0
if (isKeyPressed(Kc.VK_LEFT) && astroWalkToPlantX > 0.0) astroWalkToPlantX -= 2.0
if (flagPlantProgress > 0.0 && flagPlantProgress < 1.0) {
flagPlantProgress += 0.02
if (flagPlantProgress >= 1.0) {
isFlagPlantedOnPlanet = true
infoPanelShown = true
}
}
}
}
if (isAstronautReturningIn) {
if (astroWalkToPlantX > 0.0) astroWalkToPlantX -= 2.0
else if (doorOpeningProgress > 0.0) doorOpeningProgress -= 0.02
else { isAstronautReturningIn = false; astronautOut = false; isReturnTimerRunning = true; returnCountdownTimer = 5.0 }
}
if (isReturnTimerRunning && returnCountdownTimer > 0) { returnCountdownTimer -= 0.04; if (returnCountdownTimer <= 0) { returnCountdownTimer = 0.0; isReturnTimerRunning = false; isReturnLaunched = true } }
if (isReturnLaunched && !isLandingOnEarth && !isLandedOnEarth) {
addTricolorExhaust(rocketCurrentX, rocketCurrentY - 20); rocketCurrentY += 5.0
if (rocketCurrentY > cheight + 100.0) { isReturnLaunched = false; isLandingOnEarth = true; earthLandingProgress = 0.0; landingLegProgress = 0.0; rocketCurrentX = cwidth / 2.0; rocketCurrentY = cheight + 100.0 }
}
if (isLandingOnEarth && !isLandedOnEarth) {
addTricolorExhaust(rocketCurrentX, rocketCurrentY - 25); earthLandingProgress += 0.004
if (earthLandingProgress > 0.4 && landingLegProgress < 1.0) landingLegProgress += 0.02
if (earthLandingProgress > 0.8) addLandingDust(rocketCurrentX, 140.0)
rocketCurrentX = (cwidth / 2.0) + math.sin(earthLandingProgress * math.Pi * 5) * 18.0
rocketCurrentY = (cheight + 100.0) - ((cheight + 100.0) - 175.0) * earthLandingProgress
if (earthLandingProgress >= 1.0) { isLandingOnEarth = false; isLandedOnEarth = true; rocketCurrentX = cwidth / 2.0; rocketCurrentY = 175.0; landingLegProgress = 1.0; doorOpeningProgress = 1.0; astronautOut = true; playSoundFx(40, 250) }
}
if (isLandedOnEarth && !isParadeSceneActive) { earthAstronautWalkRightProgress += 2.8; if (earthAstronautWalkRightProgress > cwidth / 2.0 + 200.0) isParadeSceneActive = true }
if (isParadeSceneActive && !isParadeInPosition) {
if (astroParadeWalkX < (cwidth / 2.0) - 120.0) astroParadeWalkX += 1.6
if (armyParadeWalkX > (cwidth / 2.0) + 120.0) armyParadeWalkX -= 1.6
if (astroParadeWalkX >= (cwidth / 2.0) - 120.0 && armyParadeWalkX <= (cwidth / 2.0) + 120.0) { isParadeInPosition = true; startAnthemPhase = true }
}
if (isMiniGameActive) {
val gx = cwidth / 2.0 - 220.0; val gy = cheight / 2.0 - 100.0
if (isMiniGameTimerRunning) { miniGameTimer -= 0.04; if (miniGameTimer <= 0.0) { miniGameTimer = 0.0; dieAndResetDevilLevel("Time Out! Mission Failed!") } }
if (activeGameMode == 1) {
if (isKeyPressed(Kc.VK_LEFT) && dodgerShipX > gx + 25) dodgerShipX -= 7.5
if (isKeyPressed(Kc.VK_RIGHT) && dodgerShipX < gx + 415) dodgerShipX += 7.5
for (i <- 0 until dodgerCount) {
dodgerAstY(i) -= dodgerAstSpeed(i)
if (math.sqrt(math.pow(dodgerShipX - dodgerAstX(i), 2) + math.pow(dodgerShipY - dodgerAstY(i), 2)) < 22.0) dieAndResetDevilLevel("Asteroid Impact! Ship Crashed!")
if (dodgerAstY(i) < gy + 10) { dodgerAstY(i) = gy + 200.0; dodgerAstX(i) = gx + 30.0 + randomDouble(0, 380); dodgerAstSpeed(i) = randomDouble(3.0, 5.0); dodgerScore += 10; playSoundFx(72, 30) }
}
if (dodgerScore >= 80) { playSoundFx(75, 200); isMiniGameActive = false; isMiniGameTimerRunning = false; readyToReturnEarth = true; customAlertMessage = " Asteroid Belt Cleared! Return Ready!"; alertTimer = 3.5 }
} else if (activeGameMode == 3) {
val padX = gx + 180.0; val padY = gy + 20.0; val padW = 80.0
landerVy -= 0.12; landerY += landerVy; landerX += landerVx
if (isKeyPressed(Kc.VK_UP) && landerFuel > 0) { landerVy += 0.38; landerFuel -= 0.8; playSoundFx(50, 30) }
if (isKeyPressed(Kc.VK_LEFT) && landerFuel > 0) { landerVx -= 0.15; landerFuel -= 0.3 }
if (isKeyPressed(Kc.VK_RIGHT) && landerFuel > 0) { landerVx += 0.15; landerFuel -= 0.3 }
if (landerX < gx + 20) landerX = gx + 20; if (landerX > gx + 420) landerX = gx + 420
if (landerY <= gy + 30) {
if (landerX >= padX && landerX <= padX + padW && math.abs(landerVy) < 1.8) { playSoundFx(80, 250); isMiniGameActive = false; isMiniGameTimerRunning = false; readyToReturnEarth = true; customAlertMessage = " Perfect Smooth Landing Achieved!"; alertTimer = 3.5 }
else dieAndResetDevilLevel("Hard Impact! Lander Crashed!")
}
} else {
val floorY = gy + 170.0
if (isKeyPressed(Kc.VK_RIGHT) && devilPlayerX < gx + 410) devilPlayerX += 5.5
if (isKeyPressed(Kc.VK_LEFT) && devilPlayerX > gx + 15) devilPlayerX -= 5.5
val upPressedNow = isKeyPressed(Kc.VK_UP)
if (upPressedNow && !jumpKeyPressedLastFrame) {
if (isGrounded) { devilPlayerVy = -10.8; isGrounded = false; canDoubleJump = true; playSoundFx(60, 50) }
else if (canDoubleJump) { devilPlayerVy = -10.8 * 0.9; canDoubleJump = false; playSoundFx(67, 50) }
}
jumpKeyPressedLastFrame = upPressedNow
devilPlayerVy += 0.45; devilPlayerY += devilPlayerVy; devilPlayerX += devilPlayerVx; devilPlayerVx *= 0.90
if (devilPlayerX < gx + 15) devilPlayerX = gx + 15; if (devilPlayerX > gx + 410) devilPlayerX = gx + 410
if (devilPlayerY >= floorY) { devilPlayerY = floorY; devilPlayerVy = 0.0; devilPlayerVx = 0.0; isGrounded = true; canDoubleJump = true } else isGrounded = false
if (!isDevilKeyCollected && math.abs(devilPlayerX - trollKeyX) < 25 && math.abs(devilPlayerY - trollKeyY) < 25) { isDevilKeyCollected = true; playSoundFx(80, 80) }
if (isDevilKeyCollected && math.abs(devilPlayerX - exitDoorX) < 30 && math.abs(devilPlayerY - (gy + 140)) < 35) { playSoundFx(78, 200); isMiniGameActive = false; isMiniGameTimerRunning = false; readyToReturnEarth = true; customAlertMessage = " Rover Adventure Complete!"; alertTimer = 3.5 }
}
}
}
def drawParticleEffects(canvas: CanvasDraw): Unit = {
exhaustRibbons.foreach { p => val safeSize = math.max(0.1, p.size); canvas.fill(p.col.getRed, p.col.getGreen, p.col.getBlue, math.max(0, math.min(255, (p.life * 230).toInt))); canvas.noStroke(); canvas.ellipse(p.x, p.y, safeSize, math.max(0.1, safeSize * 0.6)) }
dustParticles.foreach { p => val safeSize = math.max(0.1, p.size); canvas.fill(p.col.getRed, p.col.getGreen, p.col.getBlue, math.max(0, math.min(255, (p.life * 150).toInt))); canvas.noStroke(); canvas.ellipse(p.x, p.y, safeSize, safeSize * 0.8) }
explosionParticles.foreach { p => canvas.fill(p.col.getRed, p.col.getGreen, p.col.getBlue, math.max(0, math.min(255, (p.life * 255).toInt))); canvas.noStroke(); canvas.ellipse(p.x, p.y, p.size, p.size) }
}
def draw3DSphere(canvas: CanvasDraw, cx: Double, cy: Double, size: Double, baseColor: Color, lightAccent: Color, rotAngle: Double = 0.0): Unit = {
val layers = 11; val safeSize = math.max(1.0, math.abs(size))
for (i <- 0 until layers) {
val factor = math.max(0.01, 1.0 - (i.toDouble / layers))
val r = (baseColor.getRed + (lightAccent.getRed - baseColor.getRed) * (1 - factor)).toInt
val g = (baseColor.getGreen + (lightAccent.getGreen - baseColor.getGreen) * (1 - factor)).toInt
val b = (baseColor.getBlue + (lightAccent.getBlue - baseColor.getBlue) * (1 - factor)).toInt
canvas.fill(math.max(0, math.min(255, r)), math.max(0, math.min(255, g)), math.max(0, math.min(255, b)))
canvas.noStroke()
val offset = (1 - factor) * (safeSize * 0.28)
val curDim = math.max(0.1, safeSize * factor)
canvas.ellipse(cx - offset, cy + offset, curDim, curDim)
}
canvas.fill(255, 255, 255, 45)
val spotX = cx + math.cos(rotAngle) * (safeSize * 0.25)
val spotY = cy + math.sin(rotAngle) * (safeSize * 0.15)
canvas.ellipse(spotX, spotY, math.max(0.1, safeSize * 0.35), math.max(0.1, safeSize * 0.2))
}
def project3D(x3d: Double, y3d: Double, z3d: Double, cx: Double, cy: Double): (Double, Double) = {
val cosY = math.cos(rotAngleY); val sinY = math.sin(rotAngleY)
val cosX = math.cos(rotAngleX); val sinX = math.sin(rotAngleX)
val x1 = x3d * cosY + z3d * sinY
val z1 = -x3d * sinY + z3d * cosY
val y2 = y3d * cosX - z1 * sinX
(cx + x1, cy + y2)
}
def drawFullSolarSystem(canvas: CanvasDraw): Unit = {
val (centerX, centerY) = (cwidth / 2.0 - 20.0, cheight / 2.0 - 10.0)
val pList = getActivePlanetList()
canvas.fill(0, 255, 255, 180); canvas.text("?? Drag mouse to rotate Solar System in 3D!", centerX - 120, cheight - 25)
for (i <- pList.indices) {
val radius = i * 28.0 + 50.0
canvas.noFill(); canvas.stroke(0, 255, 255, 45); canvas.strokeWeight(1.0)
canvas.ellipse(centerX, centerY, radius * 2.0, radius * 2.0 * 0.6)
}
val sunGlow = math.max(10.0, (math.sin(globalTime * 6) * 10 + 72).toDouble)
draw3DSphere(canvas, centerX, centerY, sunGlow, cm.rgb(255, 110, 0), cm.rgb(255, 255, 190), globalTime * 2)
val planetSpeeds = Array(0.7, 0.55, 0.42, 0.35, 0.28, 0.22, 0.17, 0.12)
val activeMap = getActivePlanetDetailsMap()
for (i <- pList.indices) {
val planetName = pList(i); val radius = i * 28.0 + 50.0
val angle = globalTime * (if(i < planetSpeeds.length) planetSpeeds(i) else 0.2)
val x3d = radius * math.cos(angle); val z3d = radius * math.sin(angle)
val (curX, curY) = project3D(x3d, 0.0, z3d, centerX, centerY)
var (pCol, pAccent, pRing) = (cm.rgb(200, 200, 200), cm.rgb(255, 255, 255), false)
activeMap.foreach { pd => if (pd.name == planetName) { pCol = pd.surfaceCol; pAccent = pd.accent3D; pRing = pd.hasRings } }
val pSize = math.max(1.0, if (Array("Earth", "Kepler-22b", "Kepler-452b").contains(planetName)) 18.0 else (12.0 + (i * 0.4)))
if (pRing) { canvas.noFill(); canvas.stroke(245, 220, 180, 210); canvas.strokeWeight(3.2); canvas.ellipse(curX, curY, pSize * (2.2 + math.sin(globalTime * 2) * 0.1), math.max(0.1, pSize * 0.8 * math.abs(math.cos(rotAngleX)))) }
draw3DSphere(canvas, curX, curY, pSize, pCol, pAccent, globalTime * 3 + i)
if (!planetLocked && isMousePressed && math.abs(mouseX - curX) < 20 && math.abs(mouseY - curY) < 20) {
if (planetName == "Earth") { selectedPlanet = "Earth"; customAlertMessage = "You are already on Earth!"; alertTimer = 3.0 } else selectedPlanet = planetName
}
if (planetName == selectedPlanet) { canvas.noFill(); canvas.stroke(0, 255, 255); canvas.strokeWeight(math.max(1.0, 3.0 + math.sin(neonGlowPhase * 6).toFloat * 1.5)); canvas.ellipse(curX, curY, pSize + 16, pSize + 16) }
}
}
def drawPlanetList(canvas: CanvasDraw): Unit = {
canvas.fill(15, 20, 45, 245); canvas.stroke(0, 255, 255); canvas.strokeWeight(2.5); canvas.rect(10, 10, 230, 380)
canvas.fill(255, 255, 255); canvas.text("Select Target Planet", 15, 30)
canvas.fill(0, math.max(0, math.min(255, (math.sin(globalTime * 4) * 30 + 180).toInt)), 220); canvas.stroke(255, 255, 255); canvas.strokeWeight(1.5); canvas.rect(15, 40, 220, 28)
canvas.fill(255, 255, 255); canvas.text(if (currentSolarSystemId == 1) " System: Real Solar" else " System: Kepler Planet", 18, 59)
if (isMousePressed && mouseX >= 15 && mouseX <= 235 && mouseY >= 40 && mouseY <= 68) {
currentSolarSystemId = if (currentSolarSystemId == 1) 2 else 1
selectedPlanet = if (currentSolarSystemId == 1) "Mars" else "Kepler-22b"
customAlertMessage = if (currentSolarSystemId == 1) "Real Solar System Selected!" else "Kepler Exoplanet System Selected!"
alertTimer = 2.5
}
val activeMap = getActivePlanetDetailsMap(); val pList = getActivePlanetList()
for (i <- pList.indices) {
val py = 88.0 + (i * 32.0); var rName = pList(i)
activeMap.foreach { pd => if (pd.name == pList(i)) rName = pd.realName }
if (!planetLocked && isMousePressed && mouseX >= 15 && mouseX <= 235 && mouseY >= py - 12 && mouseY <= py + 12) {
if (pList(i) == "Earth") { selectedPlanet = "Earth"; customAlertMessage = "You are already on Earth!"; alertTimer = 2.5 } else selectedPlanet = pList(i)
}
if (pList(i) == selectedPlanet) { canvas.fill(0, 180, 80); canvas.rect(15, py - 12, 220, 26); canvas.fill(255, 255, 255) } else canvas.fill(210, 210, 210)
canvas.text(s" $rName", 18, py)
}
}
def draw3DPlanetPreview(canvas: CanvasDraw): Unit = {
val (boxX, boxY, boxW, boxH) = (cwidth - 250.0, 15.0, 235.0, 225.0)
canvas.fill(15, 20, 45, 245); canvas.stroke(0, 255, 255); canvas.strokeWeight(2.0); canvas.rect(boxX, boxY, boxW, boxH)
canvas.fill(255, 255, 255); canvas.text(s"3D Hologram: $selectedPlanet", boxX + 12, boxY + 22)
val (cx, cy) = (boxX + boxW / 2.0, boxY + boxH / 2.0 + 15.0)
var (pCol, pAccent, pRings) = (cm.rgb(200, 70, 40), cm.rgb(255, 130, 100), false)
getActivePlanetDetailsMap().foreach { pd => if (pd.name == selectedPlanet) { pCol = pd.surfaceCol; pAccent = pd.accent3D; pRings = pd.hasRings } }
if (pRings) { canvas.noFill(); canvas.stroke(220, 210, 180, 230); canvas.strokeWeight(8.5); canvas.ellipse(cx, cy, 185, 54) }
draw3DSphere(canvas, cx, cy, 115, pCol, pAccent, globalTime * 2.5)
}
def drawPlanetSurfaceBackground(canvas: CanvasDraw): Unit = {
var (surfCol, darkSurfCol) = (cm.rgb(100, 30, 15), cm.rgb(50, 10, 5))
getActivePlanetDetailsMap().foreach { pd => if (pd.name == selectedPlanet) { surfCol = pd.surfaceCol; darkSurfCol = pd.darkSurfCol } }
canvas.fill(surfCol); canvas.noStroke(); canvas.rect(0, 0, cwidth, 140)
canvas.fill(darkSurfCol);
canvas.ellipse(120, 40, 60, 20); canvas.ellipse(420, 60, 90, 25); canvas.ellipse(650, 45, 70, 22); canvas.rect(0, 120, cwidth, 25)
if (isFlagPlantedOnPlanet) drawWavingTricolorFlagWithAshokChakra(canvas, plantedFlagX, plantedFlagY)
}
def drawWavingTricolorFlagWithAshokChakra(canvas: CanvasDraw, fx: Double, fy: Double): Unit = {
val (fw, fh) = (52.0, 10.0); canvas.stroke(230, 230, 230); canvas.strokeWeight(3.5); canvas.line(fx, fy + 45, fx, fy - 12)
var x = 0.0; while (x < fw) {
val yOffset = math.sin(waveAngle + (x * 0.12)) * 4.5; canvas.strokeWeight(2.8)
canvas.stroke(255, 153, 51); canvas.line(fx + x, fy + fh * 2 + yOffset, fx + x, fy + fh * 3 + yOffset)
canvas.stroke(255, 255, 255); canvas.line(fx + x, fy + fh + yOffset, fx + x, fy + fh * 2 + yOffset)
canvas.stroke(18, 136, 7); canvas.line(fx + x, fy + yOffset, fx + x, fy + fh + yOffset); x += 2.0
}
val (chakraX, chakraY) = (fx + 26.0, fy + (fh * 1.5) + math.sin(waveAngle + (26.0 * 0.12)) * 4.5)
canvas.fill(0, 0, 190); canvas.noStroke(); canvas.ellipse(chakraX, chakraY, 8.5, 8.5)
}
def drawPersonCharacter(canvas: CanvasDraw, px: Double, py: Double, isArmy: Boolean, isSaluting: Boolean): Unit = {
canvas.pushMatrix(); canvas.translate(px, py)
canvas.fill(0, 0, 0, 90); canvas.noStroke(); canvas.ellipse(0, -25, 24, 8)
val stepSwing = if (startAnthemPhase) 0.0 else math.sin(globalTime * 10) * 5.5
canvas.stroke(if (isArmy) cm.rgb(35, 65, 22) else cm.rgb(190, 190, 210)); canvas.strokeWeight(5.5)
canvas.line(-5, 0, -6 + stepSwing, -22); canvas.line(5, 0, 6 - stepSwing, -22)
canvas.fill(15, 15, 15); canvas.noStroke(); canvas.rect(-9, -25, 7, 4); canvas.rect(3, -25, 7, 4)
canvas.fill(if (isArmy) cm.rgb(80, 110, 50) else cm.rgb(245, 245, 255)); canvas.stroke(0, 255, 255); canvas.strokeWeight(1.5); canvas.rect(-10, 0, 20, 32)
canvas.fill(if (isArmy) cm.rgb(215, 165, 125) else cm.rgb(255, 255, 255)); canvas.ellipse(0, 42, 18, 18)
if (isArmy) { canvas.fill(50, 80, 30); canvas.rect(-10, 48, 20, 6) } else { canvas.fill(0, 190, 250); canvas.ellipse(0, 42, 10, 8) }
canvas.stroke(if (isArmy) cm.rgb(80, 110, 50) else cm.rgb(230, 230, 240)); canvas.strokeWeight(4.5)
if (isSaluting) { canvas.line(-8, 22, -12, 4); canvas.line(8, 22, 14, 34); canvas.line(14, 34, 8, 44) } else { canvas.line(-8, 22, -12, 4); canvas.line(8, 22, 12, 4) }
canvas.popMatrix()
}
def drawAstronautPlayer(canvas: CanvasDraw, px: Double, py: Double): Unit = {
canvas.pushMatrix()
canvas.translate(px, py)
canvas.scale(1.0, -1.0)
val floatAnim = math.sin(globalTime * 8) * 4.5
canvas.translate(0, floatAnim)
if (selectedRobotType == 1) {
canvas.fill(0, 0, 0, 80); canvas.noStroke(); canvas.ellipse(0, 32, 28, 7)
canvas.stroke(0, 255, 255); canvas.strokeWeight(5.5)
canvas.line(-7, 0, -9, 20); canvas.line(7, 0, 9, 20)
canvas.fill(15, 25, 45); canvas.stroke(0, 255, 255); canvas.strokeWeight(2.5)
canvas.rect(-14, -16, 28, 28)
canvas.fill(255, 215, 0); canvas.rect(-18, -4, 6, 12); canvas.rect(12, -4, 6, 12)
val coreGlow = (180 + math.sin(globalTime * 12) * 75).toInt
canvas.fill(0, coreGlow, 255); canvas.ellipse(0, -2, 10, 10)
canvas.fill(20, 35, 65); canvas.stroke(0, 255, 255); canvas.strokeWeight(2.0); canvas.rect(-11, -32, 22, 14)
canvas.fill(0, 255, 180); canvas.rect(-8, -28, 16, 5)
canvas.fill(255, 215, 0); canvas.ellipse(0, -35, 4, 4)
}
else if (selectedRobotType == 2) {
canvas.fill(0, 0, 0, 100); canvas.noStroke(); canvas.ellipse(0, 34, 34, 9)
canvas.stroke(255, 140, 0); canvas.strokeWeight(7.5)
canvas.line(-9, 0, -11, 20); canvas.line(9, 0, 11, 20)
canvas.fill(45, 20, 20); canvas.stroke(255, 60, 0); canvas.strokeWeight(3.0)
canvas.rect(-18, -18, 36, 30)
canvas.fill(255, 30, 30); canvas.rect(-14, -8, 28, 5)
canvas.fill(80, 80, 90); canvas.rect(-22, -12, 6, 16); canvas.rect(16, -12, 6, 16)
canvas.fill(60, 30, 30); canvas.rect(-13, -34, 26, 14)
canvas.fill(255, 220, 0); canvas.ellipse(-5, -28, 5, 5); canvas.ellipse(5, -28, 5, 5)
}
else {
canvas.fill(0, 0, 0, 80); canvas.noStroke(); canvas.ellipse(0, 32, 26, 6)
canvas.fill(80, 40, 120); canvas.stroke(200, 100, 255); canvas.strokeWeight(2.0)
canvas.ellipse(-10, 15, 10, 10); canvas.ellipse(10, 15, 10, 10)
canvas.fill(160, 40, 220); canvas.stroke(255, 150, 255); canvas.strokeWeight(2.0)
canvas.ellipse(0, -8, 28, 28)
val alienEyeGlow = (120 + math.sin(globalTime * 10) * 125).toInt
canvas.fill(0, alienEyeGlow, 255); canvas.ellipse(0, -8, 12, 12)
canvas.stroke(255, 255, 255); canvas.strokeWeight(2.5)
canvas.line(-8, 8, -12, 16); canvas.line(8, 8, 12, 16)
canvas.stroke(0, 255, 255); canvas.line(0, -22, 0, -34); canvas.fill(0, 255, 255); canvas.ellipse(0, -34, 5, 5)
}
canvas.popMatrix()
}
// --- NEW: CONTROL ROOM UNDER ROCKET VIEW SCREEN ---
def drawUnderRocketControlRoom(canvas: CanvasDraw): Unit = {
canvas.fill(10, 15, 35); canvas.noStroke(); canvas.rect(0, 0, cwidth, cheight)
// Control Room Sci-Fi Background Consoles & Screens
canvas.fill(20, 30, 60); canvas.stroke(0, 255, 255); canvas.strokeWeight(2.0)
canvas.rect(40, 40, cwidth - 80, cheight - 90)
canvas.fill(255, 215, 0); canvas.text("? ISRO ROCKET INTERIOR & ROBOT CONTROL STATION ?", cwidth / 2.0 - 210, cheight - 25)
canvas.fill(0, 255, 180); canvas.text("Astronaut inside the cockpit controlling the ground robot via neural link.", cwidth / 2.0 - 225, cheight - 50)
// Draw Seated Astronaut Inside Cockpit
val cx = cwidth / 2.0; val cy = cheight / 2.0 + 20.0
canvas.fill(40, 50, 80); canvas.stroke(0, 255, 255); canvas.strokeWeight(3.0); canvas.ellipse(cx, cy, 140, 140) // Cockpit Window / Screen
// Astronaut Head & Helmet
canvas.fill(240, 240, 255); canvas.noStroke(); canvas.ellipse(cx, cy - 10, 50, 50)
canvas.fill(0, 180, 220); canvas.ellipse(cx, cy - 10, 36, 32) // Visor reflection
// Control Consoles, Buttons & Joysticks
canvas.fill(60, 60, 80); canvas.rect(cx - 90, cy + 30, 180, 40)
canvas.fill(255, 50, 50); canvas.ellipse(cx - 60, cy + 50, 15, 15) // Red Button
canvas.fill(0, 255, 100); canvas.ellipse(cx - 20, cy + 50, 15, 15) // Green Button
canvas.fill(255, 215, 0); canvas.ellipse(cx + 20, cy + 50, 15, 15) // Yellow Button
canvas.fill(0, 150, 255); canvas.rect(cx + 45, cy + 38, 25, 24) // Joystick
canvas.fill(255, 255, 255); canvas.text("SYSTEMS ACTIVE: CONTROLLING ROBOT ?", cx - 145, cy - 85)
// --- BACK BUTTON ---
val backBtnX = 60.0; val backBtnY = cheight - 75.0
canvas.fill(200, 40, 40); canvas.stroke(255, 255, 255); canvas.strokeWeight(2.0); canvas.rect(backBtnX, backBtnY, 130, 35)
canvas.fill(255, 255, 255); canvas.text("? BACK", backBtnX + 35, backBtnY + 22)
if (isMousePressed && mouseX >= backBtnX && mouseX <= backBtnX + 130 && mouseY >= backBtnY && mouseY <= backBtnY + 35) {
isInsideUnderRocketControl = false
playSoundFx(60, 150)
}
}
def drawRobotChallengeGameScreen(canvas: CanvasDraw): Unit = {
canvas.fill(5, 5, 20); canvas.noStroke(); canvas.rect(0, 0, cwidth, cheight)
for (i <- 0 until 180) { canvas.stroke(255, 255, 255, 180); canvas.strokeWeight(starSize(i)); canvas.point(starX(i), starY(i)) }
canvas.fill(255, 215, 0); canvas.stroke(0, 255, 255); canvas.strokeWeight(3.0)
canvas.text("? ROBOT ACCESS CHALLENGE ?", cwidth / 2.0 - 140, cheight - 35)
canvas.fill(200, 240, 255); canvas.noStroke()
canvas.text(s"Catch $robotChallengeTarget Cyber Orbs using Arrow Keys [LEFT/RIGHT] to Unlock Mission Access!", cwidth / 2.0 - 230, cheight - 65)
canvas.fill(0, 255, 150); canvas.text(s"Orbs Collected: $robotChallengeScore / $robotChallengeTarget", cwidth / 2.0 - 80, cheight - 95)
val orbPulse = math.max(10.0, 15.0 + math.sin(globalTime * 10) * 5.0)
draw3DSphere(canvas, cyberEnergyX, cyberEnergyY, orbPulse, cm.rgb(0, 255, 255), cm.rgb(255, 255, 255), globalTime * 5)
drawAstronautPlayer(canvas, robotGamePlayerX, robotGamePlayerY)
}
def drawRobotSelectionScreen(canvas: CanvasDraw): Unit = {
canvas.fill(5, 8, 22); canvas.noStroke(); canvas.rect(0, 0, cwidth, cheight)
canvas.stroke(0, 255, 255, 30); canvas.strokeWeight(1.0)
for (gx <- 0 until cwidth.toInt by 40) canvas.line(gx, 0, gx, cheight)
for (gy <- 0 until cheight.toInt by 40) canvas.line(0, gy, cwidth, gy)
for (i <- 0 until 180) { canvas.stroke(255, 255, 255, 180); canvas.strokeWeight(starSize(i)); canvas.point(starX(i), starY(i)) }
val titleGlow = math.max(1.0, math.sin(globalTime * 6) * 2.5 + 4.0)
canvas.fill(255, 215, 0); canvas.stroke(255, 153, 51); canvas.strokeWeight(titleGlow)
canvas.text("? CHOOSE & UNLOCK YOUR ISRO ROBOT AVATAR ?", cwidth / 2.0 - 200, cheight - 35)
canvas.fill(200, 230, 255); canvas.noStroke()
canvas.text("Select your favourite Robot and complete the challenge to start your mission!", cwidth / 2.0 - 220, cheight - 65)
val rBoxW = 150.0; val rBoxH = 185.0; val startX = cwidth / 2.0 - 240.0; val boxY = cheight / 2.0 - 85.0
val robotNames = Array("1. NEON TITAN", "2. MECHA WARRIOR", "3. ALIEN ROVER")
val robotDescs = Array("Speed & Cyber Core", "Heavy Armor Plated", "Alien Tech & Wheels")
for (i <- 0 until 3) {
val curX = startX + (i * 170.0)
val isSelected = (selectedRobotType == i + 1)
canvas.fill(12, 22, 45, 245)
if (isSelected) { canvas.stroke(0, 255, 255); canvas.strokeWeight(3.8) }
else { canvas.stroke(80, 90, 130); canvas.strokeWeight(1.5) }
canvas.rect(curX, boxY, rBoxW, rBoxH)
canvas.fill(255, 255, 255)
canvas.text(robotNames(i), curX + 12, boxY + rBoxH - 20)
canvas.fill(0, 255, 200)
canvas.text(robotDescs(i), curX + 10, boxY + rBoxH - 38)
val tempRob = selectedRobotType
selectedRobotType = i + 1
drawAstronautPlayer(canvas, curX + rBoxW / 2.0, boxY + 68.0)
selectedRobotType = tempRob
if (isMousePressed && mouseX >= curX && mouseX <= curX + rBoxW && mouseY >= boxY && mouseY <= boxY + rBoxH) {
selectedRobotType = i + 1
playSoundFx(75, 150)
}
}
val btnX = cwidth / 2.0 - 130.0; val btnY = 30.0
if (!isRobotUnlocked) {
canvas.fill(255, 90, 0); canvas.stroke(255, 230, 0); canvas.strokeWeight(2.5); canvas.rect(btnX, btnY, 260, 42)
canvas.fill(255, 255, 255); canvas.text("UNLOCK & PLAY CHALLENGE ?", btnX + 18, btnY + 26)
if (isMousePressed && mouseX >= btnX && mouseX <= btnX + 260 && mouseY >= btnY && mouseY <= btnY + 42) {
robotChallengeScore = 0
currentStoryStage = -3
playSoundFx(80, 250)
}
} else {
canvas.fill(18, 136, 7); canvas.stroke(255, 255, 255); canvas.strokeWeight(2.5); canvas.rect(btnX, btnY, 260, 42)
canvas.fill(255, 255, 255); canvas.text("CONFIRM ROBOT ?", btnX + 60, btnY + 26)
if (isMousePressed && mouseX >= btnX && mouseX <= btnX + 260 && mouseY >= btnY && mouseY <= btnY + 42) {
currentStoryStage = -1
playSoundFx(80, 250)
}
}
}
def drawParadeGroundScene(canvas: CanvasDraw): Unit = {
canvas.fill(34, 139, 34); canvas.noStroke(); canvas.rect(0, 0, cwidth, 140); canvas.fill(25, 95, 25); canvas.rect(0, 125, cwidth, 25)
val (fx, fy, fw, fh) = (cwidth / 2.0 - 70.0, cheight / 2.0 + 10.0, 140.0, 26.0); canvas.stroke(230, 230, 230); canvas.strokeWeight(6.5); canvas.line(fx, fy + fh * 3 + 20, fx, fy - 140)
var x = 0.0; while (x < fw) {
val yOffset = math.sin(waveAngle + (x * 0.05)) * 8.5; canvas.strokeWeight(5.2)
canvas.stroke(255, 153, 51); canvas.line(fx + x, fy + fh * 2 + yOffset, fx + x, fy + fh * 3 + yOffset)
canvas.stroke(255, 255, 255); canvas.line(fx + x, fy + fh + yOffset, fx + x, fy + fh * 2 + yOffset)
canvas.stroke(18, 136, 7); canvas.line(fx + x, fy + yOffset, fx + x, fy + fh + yOffset); x += 4.0
}
canvas.fill(0, 0, 190); canvas.noStroke(); canvas.ellipse(fx + 70.0, fy + (fh * 1.5) + math.sin(waveAngle + 3.5) * 8.5, 19, 19)
petalShower.foreach { p => canvas.fill(p.col.getRed, p.col.getGreen, p.col.getBlue, 200); canvas.ellipse(p.x, p.y, p.size, p.size * 0.6) }
for (i <- 0 until 3) { drawPersonCharacter(canvas, astroParadeWalkX - (i * 35.0), 165.0, false, isParadeInPosition); drawPersonCharacter(canvas, armyParadeWalkX + (i * 35.0), 165.0, true, isParadeInPosition) }
drawPatrioticFullText(canvas)
}
def drawEarthFirstLandingScene(canvas: CanvasDraw): Unit = {
canvas.fill(34, 139, 34); canvas.noStroke(); canvas.rect(0, 0, cwidth, 140); canvas.fill(30, 110, 210); canvas.rect(0, 125, cwidth, 25); drawISRORocket(canvas)
if (isLandedOnEarth) drawPersonCharacter(canvas, rocketCurrentX + earthAstronautWalkRightProgress, 165.0, false, false)
}
def drawLaunchAndUI(canvas: CanvasDraw): Unit = {
if (!isSpaceTravelling && !isLaunched) {
val (btnX, btnY) = (cwidth - 250.0, 250.0)
if (!isTimerRunning && !quizActive) {
canvas.fill(255, 90, 0); canvas.stroke(255, 230, 0); canvas.strokeWeight(math.max(1.0, math.sin(neonGlowPhase * 5) * 2.5 + 4.5).toFloat); canvas.rect(btnX, btnY, 235, 45)
canvas.fill(255, 255, 255); canvas.text("? Launch ISRO Mission", btnX + 22, btnY + 28)
if (isMousePressed && mouseX >= btnX && mouseX <= btnX + 235 && mouseY >= btnY && mouseY <= btnY + 45) { planetLocked = true; isTimerRunning = true; countdownTimer = 10.0 }
}
if (isTimerRunning) { canvas.fill(255, 215, 0); canvas.text(s"Launch Countdown: ${countdownTimer.toInt}s", btnX + 15, btnY + 28) }
}
if (readyToReturnEarth && !isReturnLaunched && !isAstronautReturningIn && !isLandingOnEarth) {
canvas.fill(18, 136, 7); canvas.stroke(0, 255, 160); canvas.strokeWeight(math.max(1.0, math.sin(neonGlowPhase * 5) * 2.5 + 5.0).toFloat); canvas.rect(cwidth / 2.0 - 120, 25, 240, 45)
canvas.fill(255, 255, 255); canvas.text("? Return to Earth", cwidth / 2.0 - 85, 52)
if (isMousePressed && mouseX >= cwidth / 2.0 - 120 && mouseX <= cwidth / 2.0 + 120 && mouseY >= 25 && mouseY <= 70) isAstronautReturningIn = true
}
if (isReturnTimerRunning) { canvas.fill(255, 215, 0); canvas.text(s"Return Time: ${returnCountdownTimer.toInt}s", cwidth / 2.0 - 110, 80) }
}
def drawISRORocket(canvas: CanvasDraw): Unit = {
canvas.pushMatrix(); canvas.translate(rocketCurrentX, rocketCurrentY)
if (isLanded) canvas.fill(0, 0, 0, 100); canvas.noStroke(); canvas.ellipse(0, -45, 50, 12)
if (isSpaceTravelling || isLandingOnPlanet || isReturnLaunched || isLandingOnEarth) {
val flameSize = math.max(1.0, randomDouble(25.0, 42.0))
canvas.fill(255, 80, 0, 200); canvas.noStroke(); canvas.ellipse(0, -58, 22, flameSize)
canvas.fill(255, 180, 0, 230); canvas.ellipse(0, -54, 14, flameSize * 0.7)
canvas.fill(255, 255, 200, 255); canvas.ellipse(0, -50, 6, flameSize * 0.4)
}
if (!isSpaceTravelling && !isLaunched) { canvas.fill(255, 255, 255); canvas.text("ISRO", -18, 48) }
canvas.fill(245, 245, 255); canvas.stroke(0, 255, 255); canvas.strokeWeight(2.8); canvas.rect(-12, -45, 24, 45)
canvas.fill(200, 200, 215); canvas.noStroke(); canvas.rect(0, -45, 12, 45)
canvas.fill(255, 255, 255, math.max(0, math.min(255, (math.sin(globalTime * 8) * 40 + 60).toInt))); canvas.rect(-10, -42, 4, 40)
canvas.fill(255, 65, 65); canvas.stroke(255, 210, 210); canvas.strokeWeight(2.0); canvas.beginShape(); canvas.vertex(0, 25); canvas.vertex(-12, 0); canvas.vertex(12, 0); canvas.endShape()
canvas.fill(225, 225, 235); canvas.stroke(100, 100, 130); canvas.rect(-20, -35, 7, 35); canvas.rect(13, -35, 7, 35)
canvas.stroke(210, 210, 210); canvas.strokeWeight(3.8)
canvas.line(-12, -40, -12 - (landingLegProgress * 15), -45 - (landingLegProgress * 15))
canvas.line(-12 - (landingLegProgress * 15), -45 - (landingLegProgress * 15), -12 - (landingLegProgress * 22), -45 - (landingLegProgress * 15))
canvas.line(12, -40, 12 + (landingLegProgress * 15), -45 - (landingLegProgress * 15))
canvas.line(12 + (landingLegProgress * 15), -45 - (landingLegProgress * 15), 12 + (landingLegProgress * 22), -45 - (landingLegProgress * 15))
if (isLanded && !isParadeSceneActive) {
canvas.fill(40, 40, 55); canvas.rect(-8, -30, 16, math.max(0.1, 20.0 * doorOpeningProgress))
if (flagPlantProgress > 0.0 && !isFlagPlantedOnPlanet) drawWavingTricolorFlagWithAshokChakra(canvas, -80.0, -20.0)
if (astronautOut && !isLandedOnEarth) {
canvas.pushMatrix(); canvas.translate(-astroWalkToPlantX, -10.0)
drawAstronautPlayer(canvas, 0, 0)
canvas.popMatrix()
if (!isFlagPlantedOnPlanet) {
canvas.fill(0, 255, 255); canvas.text("?? Use LEFT / RIGHT Arrow Keys to Walk!", -140, 75)
}
if (astroWalkToPlantX >= 70.0 && flagPlantProgress == 0.0) {
val (flagBtnX, flagBtnY) = (-50.0, 25.0)
canvas.fill(255, 153, 51); canvas.stroke(255, 255, 255); canvas.strokeWeight(2.0)
canvas.rect(flagBtnX, flagBtnY, 110, 32)
canvas.fill(255, 255, 255); canvas.text("?? PLANT FLAG", flagBtnX + 10, flagBtnY + 20)
if (isMousePressed && mouseX >= (rocketCurrentX + flagBtnX) && mouseX <= (rocketCurrentX + flagBtnX + 110) &&
mouseY >= (rocketCurrentY + flagBtnY) && mouseY <= (rocketCurrentY + flagBtnY + 32)) {
flagPlantProgress = 0.01
playSoundFx(78, 300)
}
}
// --- NEW: "GO TO SEE UNDER ROCKET ISRO" BUTTON ---
val seeRocketBtnX = -75.0; val seeRocketBtnY = -75.0
canvas.fill(0, 180, 255); canvas.stroke(255, 255, 255); canvas.strokeWeight(2.0)
canvas.rect(seeRocketBtnX, seeRocketBtnY, 150, 32)
canvas.fill(255, 255, 255); canvas.text("GO TO SEE UNDER ROCKET ISRO", seeRocketBtnX + 5, seeRocketBtnY + 20)
if (isMousePressed && mouseX >= (rocketCurrentX + seeRocketBtnX) && mouseX <= (rocketCurrentX + seeRocketBtnX + 150) &&
mouseY >= (rocketCurrentY + seeRocketBtnY) && mouseY <= (rocketCurrentY + seeRocketBtnY + 32)) {
isInsideUnderRocketControl = true
playSoundFx(70, 200)
}
}
}
canvas.popMatrix()
}
def drawQuizPopup(canvas: CanvasDraw): Unit = {
if (quizActive) {
val (qx, qy) = (cwidth / 2.0 - 225.0, cheight / 2.0 - 130.0)
canvas.fill(15, 20, 45, 250); canvas.stroke(255, 215, 0); canvas.strokeWeight(3.5); canvas.rect(qx, qy, 450, 260)
canvas.fill(255, 255, 255); canvas.text(s"ISRO Quiz: $selectedPlanet", qx + 20, qy + 25)
var qText = ""; var opts = Array("A", "B", "C", "D"); var corr = 0
getActivePlanetDetailsMap().foreach { pd => if (pd.name == selectedPlanet) { qText = pd.quizQuestion; opts = pd.quizOptions; corr = pd.correctOpt } }
canvas.fill(255, 225, 110); canvas.text(qText, qx + 15, qy + 52)
for (i <- opts.indices) {
val optY = qy + 75.0 + (i * 32.0); canvas.fill(30, 45, 85); canvas.stroke(0, 255, 255); canvas.strokeWeight(1.5); canvas.rect(qx + 15, optY, 420, 26)
canvas.fill(255, 255, 255); canvas.text(opts(i), qx + 25, optY + 18)
if (isMousePressed && mouseX >= qx + 15 && mouseX <= qx + 435 && mouseY >= optY && mouseY <= optY + 26) {
if (i == corr) { quizActive = false; isSpaceTravelling = true; spaceTravelProgress = 0.0; customAlertMessage = "Correct Answer! Mission Continues!"; alertTimer = 3.0 }
else quizFeedback = "Incorrect Answer! Try Again."
}
}
if (quizFeedback != "") { canvas.fill(255, 60, 60); canvas.text(quizFeedback, qx + 20, qy + 235) }
}
}
def drawPlanetInfoPopup(canvas: CanvasDraw): Unit = {
if (infoPanelShown) {
val (ix, iy) = (cwidth / 2.0 - 230.0, cheight / 2.0 - 130.0)
canvas.fill(15, 20, 45, 250); canvas.stroke(0, 255, 255); canvas.strokeWeight(3.5); canvas.rect(ix, iy, 460, 260)
val signalGlow = math.max(0, math.min(255, (math.sin(globalTime * 10) * 100 + 155).toInt))
canvas.fill(0, signalGlow, 255); canvas.noStroke(); canvas.ellipse(ix + 430, iy + 25, 10, 10)
var rName = selectedPlanet; val activeMap = getActivePlanetDetailsMap()
activeMap.foreach { pd => if (pd.name == selectedPlanet) rName = pd.realName }
canvas.fill(255, 215, 0); canvas.text(s" Mission Info: $rName (Page $infoPageNumber/3)", ix + 20, iy + 25)
var (l1, l2, l3, l4, l5, l6, l7, l8) = ("", "", "", "", "", "", "", "")
activeMap.foreach { pd => if (pd.name == selectedPlanet) { l1 = pd.infoLine1; l2 = pd.infoLine2; l3 = pd.infoLine3; l4 = pd.infoLine4; l5 = pd.infoLine5; l6 = pd.infoLine6; l7 = pd.infoLine7; l8 = pd.infoLine8 } }
if (infoPageNumber == 1) { canvas.fill(100, 225, 255); canvas.text(" Primary Planetary Characteristics:", ix + 20, iy + 52); canvas.fill(225, 225, 245); canvas.text(l1, ix + 20, iy + 80); canvas.text(l2, ix + 20, iy + 110); canvas.text(l3, ix + 20, iy + 140) }
else if (infoPageNumber == 2) { canvas.fill(100, 255, 210); canvas.text(" Real Scientific & Distance Data:", ix + 20, iy + 52); canvas.fill(225, 225, 245); canvas.text(l4, ix + 20, iy + 80); canvas.text(l5, ix + 20, iy + 110); canvas.text(l6, ix + 20, iy + 140) }
else { canvas.fill(255, 190, 110); canvas.text(" Atmospheric Spectrum & ISRO Notes:", ix + 20, iy + 52); canvas.fill(225, 225, 245); canvas.text(l7, ix + 20, iy + 80); canvas.text(l8, ix + 20, iy + 110) }
canvas.fill(45, 110, 210); canvas.rect(ix + 20, iy + 195, 100, 35); canvas.fill(255, 255, 255); canvas.text("Next Page", ix + 30, iy + 218)
if (isMousePressed && mouseX >= ix + 20 && mouseX <= ix + 120 && mouseY >= iy + 195 && mouseY <= iy + 230) infoPageNumber = if (infoPageNumber == 3) 1 else infoPageNumber + 1
canvas.fill(0, 190, 90); canvas.rect(ix + 140, iy + 195, 150, 35); canvas.fill(255, 255, 255); canvas.text(" Play Game", ix + 170, iy + 218)
if (isMousePressed && mouseX >= ix + 140 && mouseX <= ix + 290 && mouseY >= ix + 195 && mouseY <= iy + 230) { infoPanelShown = false; isMiniGameActive = true; dieAndResetDevilLevel("Game Started!") }
canvas.fill(190, 45, 45); canvas.rect(ix + 300, iy + 195, 130, 35); canvas.fill(255, 255, 255); canvas.text("Close X", ix + 325, iy + 218)
if (isMousePressed && mouseX >= ix + 300 && mouseX <= ix + 430 && mouseY >= ix + 195 && mouseY <= iy + 230) { infoPanelShown = false; readyToReturnEarth = true }
}
}
def drawCustomAlertPopup(canvas: CanvasDraw): Unit = {
if (alertTimer > 0 && customAlertMessage != "") {
canvas.fill(230, 35, 35, 240); canvas.stroke(255, 255, 255); canvas.strokeWeight(2.2); canvas.rect(cwidth / 2.0 - 210.0, 80.0, 420, 50)
canvas.fill(255, 255, 255); canvas.text(customAlertMessage, cwidth / 2.0 - 195.0, 110.0)
}
}
def drawMiniGames(canvas: CanvasDraw): Unit = {
if (isMiniGameActive) {
val (gx, gy) = (cwidth / 2.0 - 220.0, cheight / 2.0 - 100.0)
canvas.fill(10, 10, 25, 250); canvas.stroke(0, 255, 210); canvas.strokeWeight(3.5); canvas.rect(gx, gy, 440, 210)
canvas.fill(255, 65, 65); canvas.text(s" Time: ${miniGameTimer.toInt}s", gx + 290, gy + 190)
if (activeGameMode == 1) {
canvas.fill(255, 255, 255); canvas.text(s" Asteroid Dodger | Score: $dodgerScore/80", gx + 15, gy + 190)
canvas.fill(0, 255, 210); canvas.stroke(255, 255, 255); canvas.strokeWeight(1.5)
canvas.beginShape(); canvas.vertex(dodgerShipX, dodgerShipY + 12); canvas.vertex(dodgerShipX - 12, dodgerShipY - 12); canvas.vertex(dodgerShipX + 12, dodgerShipY - 12); canvas.endShape()
for (i <- 0 until dodgerCount) draw3DSphere(canvas, dodgerAstX(i), dodgerAstY(i), 22, cm.rgb(190, 110, 70), cm.rgb(255, 190, 110), globalTime * 2)
} else if (activeGameMode == 3) {
val (padX, padY, padW) = (gx + 180.0, gy + 20.0, 80.0)
canvas.fill(255, 255, 255); canvas.text(s" Lander Fuel: ${landerFuel.toInt}%", gx + 15, gy + 190)
canvas.fill(0, 255, 110); canvas.rect(padX, padY, padW, 8); canvas.fill(255, 255, 255); canvas.text("TARGET PAD", padX + 5, padY + 18)
canvas.fill(255, 210, 0); canvas.stroke(255, 255, 255); canvas.strokeWeight(1.5); canvas.rect(landerX - 12, landerY - 12, 24, 24)
if (isKeyPressed(Kc.VK_UP) && landerFuel > 0) { canvas.fill(255, 110, 0); canvas.noStroke(); canvas.ellipse(landerX, landerY - 20, 10, 16) }
} else {
canvas.fill(255, 255, 255); canvas.text(s" Rover Adventure Game", gx + 15, gy + 190)
canvas.fill(255, 153, 51); canvas.rect(gx + 15, gy + 170, 410, 12)
if (!isDevilKeyCollected) { canvas.fill(255, 215, 0); canvas.ellipse(trollKeyX, trollKeyY, 16, 16) }
canvas.fill(if (isDevilKeyCollected) cm.rgb(0, 255, 160) else cm.rgb(110, 110, 110)); canvas.rect(exitDoorX, gy + 135, 30, 40)
drawAstronautPlayer(canvas, devilPlayerX, devilPlayerY)
}
}
}
def drawPatrioticFullText(canvas: CanvasDraw): Unit = {
if (charIndex > 0) {
val lines = fullAnthemText.substring(0, charIndex).split("\n"); var startY = cheight - 40.0
for (i <- lines.indices) {
canvas.fill(255, 215, 0, 110); canvas.text(lines(i), 21.0, startY - 1)
canvas.fill(255, 255, 255); canvas.text(lines(i), 20.0, startY); startY -= 18.0
}
}
}
def drawCleanEndScreen(canvas: CanvasDraw): Unit = {
canvas.fill(0, 0, 0); canvas.noStroke(); canvas.rect(0, 0, cwidth, cheight)
val (centerX, centerY) = (cwidth / 2.0, cheight / 2.0); val glowFactor = math.max(1.0, (math.sin(globalTime * 5) * 2 + 4.0).toFloat)
canvas.fill(255, 215, 0); canvas.stroke(255, 160, 0); canvas.strokeWeight(glowFactor);
canvas.text("Thank You! Mission Complete (THE END)", centerX - 150.0, centerY + 80.0)
canvas.fill(0, 255, 255); canvas.stroke(0, 190, 255); canvas.strokeWeight(glowFactor * 0.8);
canvas.text("Made by Yadnesh Shahare and Bhavesh Shahare", centerX - 200.0, centerY + 30.0)
canvas.fill(255, 255, 255); canvas.stroke(255, 255, 255); canvas.strokeWeight(glowFactor * 0.5);
canvas.text("Jai Hind! Jai Bharat!", centerX - 80.0, centerY - 20.0)
canvas.fill(180, 100, 255); canvas.stroke(220, 150, 255); canvas.strokeWeight(glowFactor * 0.5);
canvas.text("Next part in my brother PC", centerX - 115.0, centerY - 80.0)
}
def drawWelcomeSirScreen(canvas: CanvasDraw): Unit = {
canvas.fill(0, 5, 20); canvas.noStroke(); canvas.rect(0, 0, cwidth, cheight)
for (i <- 0 until 180) { canvas.stroke(255, 255, 255, 180); canvas.strokeWeight(starSize(i)); canvas.point(starX(i), starY(i)) }
val pulseGlow = math.max(1.0, math.sin(welcomeTimer * 5) * 3 + 5)
canvas.fill(255, 215, 0); canvas.stroke(255, 153, 51); canvas.strokeWeight(pulseGlow)
canvas.text("WELCOME SIR", cwidth / 2.0 - 70, cheight / 2.0 + 60)
canvas.fill(0, 255, 255); canvas.stroke(0, 180, 255); canvas.strokeWeight(pulseGlow * 0.8)
canvas.text("TO ISRO GAGANYAAN 3D SPACE MISSION CODE", cwidth / 2.0 - 180, cheight / 2.0 + 20)
canvas.fill(220, 240, 255); canvas.noStroke()
canvas.text("? Features: Real Planetary Data | 3D Controls | Exoplanets System ?", cwidth / 2.0 - 210, cheight / 2.0 - 30)
canvas.text("? Advanced Mini-Games | Dynamic Astronaut Simulations | Patriotic Finale ?", cwidth / 2.0 - 225, cheight / 2.0 - 60)
canvas.fill(0, 255, 150)
canvas.text(s"Initializing Mission Call Letter... (${(7.5 - welcomeTimer).max(0.0).toInt + 1}s)", cwidth / 2.0 - 130, cheight / 2.0 - 110)
}
def drawISROLetterScreen(canvas: CanvasDraw): Unit = {
canvas.fill(5, 10, 25); canvas.noStroke(); canvas.rect(0, 0, cwidth, cheight)
val (lx, ly, lw, lh) = (cwidth / 2.0 - 260.0, cheight / 2.0 - 150.0, 520.0, 310.0)
canvas.fill(15, 25, 50, 240); canvas.stroke(255, 153, 51); canvas.strokeWeight(3.0); canvas.rect(lx, ly, lw, lh)
canvas.fill(255, 215, 0); canvas.text("?? ISRO OFFICIAL INVITATION LETTER ??", lx + 100, ly + 25)
if (letterTextTyped > 0) {
val printedText = officialLetterText.substring(0, letterTextTyped)
val lines = printedText.split("\n"); var currY = ly + 55.0
for (line <- lines) { canvas.fill(220, 240, 255); canvas.text(line, lx + 20, currY); currY += 18.0 }
}
if (letterTextTyped >= officialLetterText.length) {
val btnX = lx + 160.0; val btnY = ly - 40.0
canvas.fill(18, 136, 7); canvas.stroke(255, 255, 255); canvas.strokeWeight(2.0); canvas.rect(btnX, btnY, 200, 35)
canvas.fill(255, 255, 255); canvas.text("ACCEPT MISSION ?", btnX + 35, btnY + 22)
if (isMousePressed && mouseX >= btnX && mouseX <= btnX + 200 && mouseY >= btnY && mouseY <= btnY + 35) { currentStoryStage = 1; playSoundFx(75, 250) }
}
}
def drawPartOneTitleScreen(canvas: CanvasDraw): Unit = {
canvas.fill(0, 0, 0); canvas.noStroke(); canvas.rect(0, 0, cwidth, cheight)
val glow = math.max(1.0, math.sin(titleCardTimer * 4) * 3 + 5)
canvas.fill(0, 255, 255); canvas.stroke(0, 180, 255); canvas.strokeWeight(glow); canvas.text("CHAPTER 1", cwidth / 2.0 - 45, cheight / 2.0 + 40)
canvas.fill(255, 215, 0); canvas.stroke(255, 153, 51); canvas.strokeWeight(glow * 1.2); canvas.text("PART 1: THE ASTRONAUT", cwidth / 2.0 - 110, cheight / 2.0 - 10)
canvas.fill(200, 200, 200); canvas.noStroke(); canvas.text("Preparing Gaganyaan Space Launch Sequence...", cwidth / 2.0 - 140, cheight / 2.0 - 60)
}
def viewState(canvas: CanvasDraw): Unit = {
if (currentStoryStage == -3) drawRobotChallengeGameScreen(canvas)
else if (currentStoryStage == -2) drawRobotSelectionScreen(canvas)
else if (currentStoryStage == -1) drawWelcomeSirScreen(canvas)
else if (currentStoryStage == 0) drawISROLetterScreen(canvas)
else if (currentStoryStage == 1) drawPartOneTitleScreen(canvas)
else {
if (isInsideUnderRocketControl) {
drawUnderRocketControlRoom(canvas)
} else {
if (anthemFinished) drawCleanEndScreen(canvas)
else {
canvas.fill(0, 0, 0, 255); canvas.noStroke(); canvas.rect(0, 0, cwidth, cheight)
for (i <- 0 until starCount) {
val starAlpha = math.max(50, math.min(255, (150 + math.sin(globalTime * 5 + i) * 105).toInt))
canvas.stroke(255, 255, 255, starAlpha); canvas.strokeWeight(math.max(0.1, starSize(i) + (math.sin(globalTime * 6 + i).toFloat * 1.1)))
canvas.point(starX(i), starY(i))
}
drawParticleEffects(canvas)
if (isParadeSceneActive) drawParadeGroundScene(canvas)
else if (isLandingOnEarth || isLandedOnEarth) drawEarthFirstLandingScene(canvas)
else {
if (isLaunched) drawPlanetSurfaceBackground(canvas)
else { drawFullSolarSystem(canvas); drawPlanetList(canvas); draw3DPlanetPreview(canvas) }
drawLaunchAndUI(canvas); drawISRORocket(canvas)
}
drawQuizPopup(canvas); drawPlanetInfoPopup(canvas); drawMiniGames(canvas); drawCustomAlertPopup(canvas)
}
}
}
}
animateWithCanvasDraw { canvas => updateState(); viewState(canvas) }