Code Sketch
Bixuu02
Category: Programming
import scala.collection.mutable.ArrayBuffer
cleari()
originBottomLeft()
// ============================================================
// OPERATION SINDOOR - ADVANCED SAINIK COMMAND EDITION
// KOJO / CANVASDRAW
// Password: yadnesh
// ============================================================
var currentGameState = -1
val ENGINE_VERSION = "V14.0 - ADVANCED COMMAND"
// ============================================================
// PASSWORD SECURITY
// ============================================================
val missionPassword = "yadnesh"
var passwordUnlocked = false
var passwordInput = ""
var passwordErrorTimer = 0.0
var passwordSuccessPulse = 0.0
var keyYLast = false
var keyDLast = false
var keyNLast = false
var keyEPassLast = false
var keySLast = false
var keyHLast = false
var keyAAllLast = false
var keyRLast = false
var keySpaceLast = false
// ============================================================
// AVATAR SYSTEM
// ============================================================
var selectedAvatar = 1
var avatarHover = 0
var avatarLocked = false
var avatarTransition = 0.0
var avatarSelectFlash = 0.0
var avatarFloat = 0.0
val avatarNames = Array("NEON COMMANDER","IRON DEFENDER","SHADOW SCOUT","QUANTUM SPECIALIST")
val avatarRoles = Array("TACTICAL COMMAND","HEAVY DEFENSE","RAPID RESPONSE","ENERGY SYSTEMS")
// ============================================================
// CLOCKS / MISSION
// ============================================================
var universalClock = 0.0
var briefingIndex = 0
var briefingTimer = 0.0
var combatTimer = 100.0
var scoreDestroyedCount = 0
val quotaRequirement = 35
// ============================================================
// COMMANDER
// ============================================================
var commanderHP = 100.0
var commanderX = cwidth / 2.0
var commanderY = 145.0
var commanderPulse = 0.0
// ============================================================
// TANK
// ============================================================
var tankX = cwidth / 2.0 + 90.0
val tankY = 32.0
var turretAngle = math.Pi / 2.0
var tankRecoil = 0.0
var tankHeat = 0.0
var tankEngine = 0.0
var cannonFlash = 0
var cannonCooldown = 0
var missileLaunchPulse = 0.0
var missileLaunchSoundCooldown = 0
// ============================================================
// SILO / AIR DEFENSE
// ============================================================
var siloX = cwidth / 2.0 - 260.0
var siloY = 145.0
var siloAngle = math.Pi / 2.0
var missileType = 1
var missileCooldown = 0
var akashX = cwidth / 2.0 - 90.0
var akashY = 110.0
var pinakaX = cwidth / 2.0 + 200.0
var pinakaY = 120.0
var akashAngle = 0.0
var pinakaPulse = 0.0
var pinakaCooldown = 0
// ============================================================
// BOSS / FINAL STRIKE
// ============================================================
var bossActive = false
var bossX = cwidth / 2.0
var bossY = cheight - 145.0
var bossHP = 800.0
val bossMaxHP = 800.0
var bossShield = 100.0
var bossPhase = 1
var bossMovement = 0.0
var bossCore = 0.0
var strikeX = 0.0
var strikeY = 0.0
var strikeAngle = math.Pi / 2.0
var strikeSpeed = 8.5
// ============================================================
// FX
// ============================================================
var screenShake = 0.0
var colorFlash = 0.0
var redAlert = 0.0
var cinematicBars = 0.0
var scanPulse = 0.0
var gridPulse = 0.0
// ============================================================
// SQUAD
// ============================================================
val squadCount = 4
var squadDeploy = 0.0
var squadMarch = 0.0
var squadSalute = 0.0
var squadScan = 0.0
var squadDrone = 0.0
// ============================================================
// BRIEFING
// ============================================================
val briefingText =
"TOP SECRET DIRECTIVE: OPERATION SINDOOR\n" +
"DEFENSE STRATEGIC COMMAND NETWORK\n\n" +
"MULTIPLE HOSTILE SIGNALS DETECTED.\n" +
"PERIMETER STATUS: CRITICAL.\n\n" +
"SAINIK COMMAND SQUAD: READY\n" +
"MAIN BATTLE TANK: READY\n" +
"AKASH AIR DEFENSE: ONLINE\n" +
"PINAKA ROCKET GRID: ONLINE\n" +
"COMMAND DRONE: ONLINE\n" +
"QUANTUM LINK: STABLE\n\n" +
"OBJECTIVES:\n" +
"DEFEND THE SECTOR.\n" +
"NEUTRALIZE HOSTILE WAVES.\n" +
"DEFEAT THE FLAGSHIP.\n\n" +
"INITIALIZE HYPER DEFENSE."
// ============================================================
// AUDIO
// ============================================================
var audioEnabled = false
try {
setNoteInstrument(Instrument.SYNTH_STRINGS)
audioEnabled = true
} catch {
case _: Exception => audioEnabled = false
}
def playFX(note: Int, duration: Int): Unit = {
if (audioEnabled) {
try { playNote(note, duration) } catch { case _: Exception => }
}
}
// ============================================================
// STARS
// ============================================================
val MAX_STARS = 520
val MAX_PARTICLES = 1300
val MAX_SHOCKWAVES = 70
val MAX_ENEMIES = 75
val starX = Array.fill(MAX_STARS)(randomDouble(0.0, cwidth))
val starY = Array.fill(MAX_STARS)(randomDouble(50.0, cheight))
val starSize = Array.fill(MAX_STARS)(randomDouble(0.5, 3.6))
val starSpeed = Array.fill(MAX_STARS)(randomDouble(0.5, 4.0))
// ============================================================
// PARTICLES
// ============================================================
case class Particle(var x: Double,var y: Double,var vx: Double,var vy: Double,var life: Double,val r: Int,val g: Int,val b: Int,var size: Double)
val particles = ArrayBuffer.empty[Particle]
def spawnParticles(x: Double,y: Double,r: Int,g: Int,b: Int,count: Int): Unit = {
var i = 0
while (i < count && particles.length < MAX_PARTICLES) {
particles.append(Particle(x,y,randomDouble(-7.5,7.5),randomDouble(-7.5,7.5),1.0,r,g,b,randomDouble(2.0,9.0)))
i += 1
}
}
def updateParticles(): Unit = {
particles.filterInPlace(_.life > 0.0)
particles.foreach { p =>
p.x += p.vx
p.y += p.vy
p.vx *= 0.965
p.vy *= 0.965
p.life -= 0.024
p.size *= 0.986
}
}
def drawParticles(c: CanvasDraw): Unit = {
particles.foreach { p =>
val alpha = math.max(0, math.min(255, (p.life * 255.0).toInt))
c.fill(p.r,p.g,p.b,alpha)
c.noStroke()
c.ellipse(p.x,p.y,p.size,p.size)
}
}
// ============================================================
// SHOCKWAVES
// ============================================================
class Shockwave(val x: Double,val y: Double,val kind: Int) {
var radius = 5.0
var life = 255.0
def update(): Unit = { radius += 10.0; life -= 13.0 }
def draw(c: CanvasDraw): Unit = {
if (life > 0.0) {
c.noFill()
if (kind == 0) c.stroke(0,255,255,life.toInt)
else if (kind == 1) c.stroke(255,180,50,life.toInt)
else c.stroke(255,60,60,life.toInt)
c.strokeWeight(3.0)
c.ellipse(x,y,radius*2.0,radius*2.0)
}
}
}
val shockwaves = ArrayBuffer.empty[Shockwave]
// ============================================================
// SHELLS
// ============================================================
class Shell(var x: Double,var y: Double,val vx: Double,val vy: Double) {
var active = true
val trail = ArrayBuffer.empty[(Double,Double)]
def update(): Unit = {
x += vx
y += vy
trail.append((x,y))
if (trail.length > 14) trail.remove(0)
if (x < -100 || x > cwidth + 100 || y < -100 || y > cheight + 100) active = false
}
def draw(c: CanvasDraw): Unit = {
var i = 0
while (i < trail.length) {
val p = trail(i)
c.fill(255,150,30,(i.toDouble / trail.length * 180.0).toInt)
c.noStroke()
c.ellipse(p._1,p._2,4.0,4.0)
i += 1
}
c.fill(255,245,175)
c.noStroke()
c.ellipse(x,y,12.0,12.0)
}
}
val shells = ArrayBuffer.empty[Shell]
// ============================================================
// MISSILES
// ============================================================
class Missile(var x: Double,var y: Double,val speed: Double,var angle: Double,val kind: Int) {
var active = true
val trail = ArrayBuffer.empty[(Double,Double)]
def update(): Unit = {
if (kind == 2) angle += 0.025
if (kind == 3) angle += math.sin(universalClock*8.0)*0.05
x += math.cos(angle) * speed
y += math.sin(angle) * speed
trail.append((x,y))
if (trail.length > 25) trail.remove(0)
if (x < -150 || x > cwidth+150 || y < -150 || y > cheight+150) active = false
spawnParticles(x - math.cos(angle)*18.0,y - math.sin(angle)*18.0,40,210,255,1)
}
def draw(c: CanvasDraw): Unit = {
var i = 0
while (i < trail.length) {
val p = trail(i)
val aa = (i.toDouble/trail.length*210.0).toInt
if (kind == 1) c.fill(0,255,230,aa)
else if (kind == 2) c.fill(255,170,40,aa)
else c.fill(255,70,40,aa)
c.noStroke()
c.ellipse(p._1,p._2,5.0,5.0)
i += 1
}
c.pushMatrix()
c.translate(x,y)
c.rotate(angle)
c.fill(235,250,255)
c.stroke(0,110,150)
c.strokeWeight(1.2)
c.rect(-25,-7,50,14)
c.fill(0,245,255)
c.noStroke()
c.ellipse(25,0,15,15)
c.popMatrix()
}
}
val missiles = ArrayBuffer.empty[Missile]
// ============================================================
// ENEMIES
// ============================================================
class Enemy(var x: Double,var y: Double,val speed: Double,val pattern: Int) {
var active = true
var destroyed = false
var angle = 0.0
val trail = ArrayBuffer.empty[(Double,Double)]
def update(): Unit = {
if (!destroyed) {
y += speed
angle += 0.07
if (pattern == 1) x += math.sin(universalClock*4.0+y*0.02)*3.0
if (pattern == 2) x += math.sin(universalClock*6.0+y*0.02)*5.0
if (pattern == 3) x += math.cos(universalClock*7.0+y*0.025)*7.0
if (pattern == 4) x += math.sin(universalClock*10.0+y*0.04)*9.0
trail.append((x,y))
if (trail.length > 20) trail.remove(0)
if (y < -100) active = false
}
}
def draw(c: CanvasDraw): Unit = {
if (!destroyed) {
var i = 0
while (i < trail.length) {
val p = trail(i)
c.fill(255,40,60,(i.toDouble/trail.length*165.0).toInt)
c.noStroke()
c.ellipse(p._1,p._2,4,4)
i += 1
}
c.pushMatrix()
c.translate(x,y)
c.rotate(math.sin(angle)*0.18)
c.fill(70,15,20)
c.stroke(170,25,35)
c.strokeWeight(2)
c.rect(-28,-8,56,16)
c.fill(210,40,45)
c.rect(-17,-14,34,28)
c.fill(255,170,40)
c.noStroke()
c.ellipse(22,0,14,14)
c.popMatrix()
}
}
}
val enemies = ArrayBuffer.empty[Enemy]
// ============================================================
// EXPLOSIONS
// ============================================================
def explosion(x: Double,y: Double,power: Int): Unit = {
shockwaves.append(new Shockwave(x,y,1))
if (shockwaves.length > MAX_SHOCKWAVES) shockwaves.remove(0)
spawnParticles(x,y,255,190,50,power)
spawnParticles(x,y,255,60,30,power/2)
screenShake = math.max(screenShake,7.0 + power*0.15)
colorFlash = math.max(colorFlash,0.25)
}
def megaExplosion(x: Double,y: Double): Unit = {
explosion(x,y,45)
shockwaves.append(new Shockwave(x,y,0))
shockwaves.append(new Shockwave(x,y,2))
spawnParticles(x,y,255,255,220,35)
screenShake = 18.0
colorFlash = 0.65
playFX(42,100)
}
// ============================================================
// AVATAR DRAW
// ============================================================
def drawAvatar(c: CanvasDraw,x: Double,y: Double,avatarType: Int,scale: Double,selected: Boolean,salute: Boolean): Unit = {
c.pushMatrix()
c.translate(x,y)
c.scale(scale,scale)
val breath = math.sin(avatarFloat*2.0)*1.5
val walk = math.sin(squadMarch)*4.0
if (selected) {
c.noFill()
c.stroke(0,255,255,150)
c.strokeWeight(2.5)
c.ellipse(0,30,105+math.sin(avatarFloat*3.0)*8.0,145)
c.stroke(255,215,60,100)
c.ellipse(0,30,125+math.sin(avatarFloat*2.0)*8.0,165)
}
c.fill(0,0,0,110); c.noStroke(); c.ellipse(0,-35,60,12)
c.stroke(35,45,52); c.strokeWeight(7)
c.line(-9,0,-14+walk,-31); c.line(9,0,14-walk,-31)
c.stroke(15,20,25); c.strokeWeight(8)
c.line(-14+walk,-31,-22+walk,-36); c.line(14-walk,-31,22-walk,-36)
if (avatarType == 1) { c.fill(45,75,85); c.stroke(0,220,255) }
else if (avatarType == 2) { c.fill(72,67,58); c.stroke(255,165,50) }
else if (avatarType == 3) { c.fill(35,40,60); c.stroke(175,80,255) }
else { c.fill(35,68,58); c.stroke(0,255,180) }
c.strokeWeight(2); c.rect(-20,breath,40,43)
if (avatarType == 1) c.fill(0,220,255)
else if (avatarType == 2) c.fill(255,100,30)
else if (avatarType == 3) c.fill(185,75,255)
else c.fill(0,255,180)
c.noStroke(); c.ellipse(0,21+breath,10,10)
c.stroke(55,75,82); c.strokeWeight(6)
if (salute) {
c.line(-15,28,-22,46); c.line(15,28,21,46)
} else {
c.line(-15,28,-26,7); c.line(15,28,26,7)
}
c.fill(170,125,85); c.noStroke(); c.rect(-7,38,14,10)
c.fill(52,70,78); c.stroke(10,22,28); c.strokeWeight(2); c.ellipse(0,68+breath,50,45)
if (avatarType == 1) { c.fill(5,35,48); c.stroke(0,235,255) }
else if (avatarType == 2) { c.fill(75,35,25); c.stroke(255,170,50) }
else if (avatarType == 3) { c.fill(30,15,60); c.stroke(190,90,255) }
else { c.fill(5,45,35); c.stroke(0,255,180) }
c.strokeWeight(2.5); c.ellipse(0,66+breath,34,20)
val lightPulse = 120 + (math.abs(math.sin(avatarFloat*3.0))*120.0).toInt
if (avatarType == 3) c.fill(190,80,lightPulse)
else if (avatarType == 4) c.fill(0,lightPulse,180)
else c.fill(0,lightPulse,255)
c.noStroke(); c.ellipse(0,91+breath,6,6)
c.fill(255,153,51); c.rect(-27,12,6,5)
c.fill(255,255,255); c.rect(-27,17,6,5)
c.fill(18,136,7); c.rect(-27,22,6,5)
c.popMatrix()
}
// ============================================================
// STARFIELD
// ============================================================
def drawStarfield(c: CanvasDraw): Unit = {
var i = 0
while (i < MAX_STARS) {
val alpha = math.max(55,math.min(255,(75+math.abs(math.sin(universalClock*starSpeed(i)+i))*180).toInt))
var yy = starY(i) - universalClock*starSpeed(i)*5.0
while (yy < 45) yy += cheight-45
c.fill(225,240,255,alpha); c.noStroke(); c.ellipse(starX(i),yy,starSize(i),starSize(i))
i += 1
}
}
// ============================================================
// PASSWORD INPUT
// ============================================================
def passwordChar(ch: Char): Unit = {
if (passwordUnlocked) return
if (passwordInput.length < missionPassword.length) passwordInput += ch
if (passwordInput == missionPassword) {
passwordUnlocked = true
passwordInput = ""
passwordSuccessPulse = 1.0
currentGameState = -2
avatarLocked = false
playFX(84,180)
} else if (passwordInput.length >= missionPassword.length) {
passwordInput = ""
passwordErrorTimer = 1.8
playFX(40,120)
}
}
def updatePassword(): Unit = {
if (passwordUnlocked) return
if (passwordErrorTimer > 0) passwordErrorTimer -= 0.04
val y = isKeyPressed(Kc.VK_Y)
val d = isKeyPressed(Kc.VK_D)
val n = isKeyPressed(Kc.VK_N)
val e = isKeyPressed(Kc.VK_E)
val s = isKeyPressed(Kc.VK_S)
val h = isKeyPressed(Kc.VK_H)
val a = isKeyPressed(Kc.VK_A)
val r = isKeyPressed(Kc.VK_R)
val sp = isKeyPressed(Kc.VK_SPACE)
if (y && !keyYLast) passwordChar('y')
if (d && !keyDLast) passwordChar('d')
if (n && !keyNLast) passwordChar('n')
if (e && !keyEPassLast) passwordChar('e')
if (s && !keySLast) passwordChar('s')
if (h && !keyHLast) passwordChar('h')
if (a && !keyAAllLast) passwordChar('a')
if (r && !keyRLast) passwordChar('r')
if (sp && !keySpaceLast) passwordChar(' ')
keyYLast = y; keyDLast = d; keyNLast = n; keyEPassLast = e; keySLast = s; keyHLast = h; keyAAllLast = a; keyRLast = r; keySpaceLast = sp
}
// ============================================================
// PASSWORD SCREEN
// ============================================================
def drawPasswordScreen(c: CanvasDraw): Unit = {
c.background(1,3,14)
drawStarfield(c)
val cx = cwidth/2.0
val cy = cheight/2.0
val glow = 3.0 + math.abs(math.sin(avatarFloat*2.0))*2.0
c.fill(6,18,42,250); c.stroke(0,255,255); c.strokeWeight(glow); c.rect(cx-275,cy-165,550,330)
c.fill(0,255,230); c.text("DEFENSE COMMAND SECURITY",cx-132,cy+120)
c.fill(255,215,60); c.text("OPERATION SINDOOR",cx-82,cy+88)
c.fill(25,35,60); c.stroke(0,220,255); c.strokeWeight(3); c.rect(cx-42,cy-28,84,65)
c.noFill(); c.stroke(0,220,255); c.strokeWeight(5)
c.line(cx-28,cy-28,cx-28,cy-52); c.line(cx-28,cy-52,cx,cy-68); c.line(cx,cy-68,cx+28,cy-52); c.line(cx+28,cy-52,cx+28,cy-28)
c.fill(255,215,60); c.noStroke(); c.ellipse(cx,cy,10,10)
c.fill(170,210,230); c.text("ENTER ACCESS PASSWORD",cx-105,cy-88)
c.fill(4,22,40); c.stroke(0,210,255); c.strokeWeight(2); c.rect(cx-135,cy-130,270,38)
val masked = passwordInput.map(_ => "*").mkString
c.fill(0,255,180); c.noStroke(); c.text(masked,cx-110,cy-105)
if (passwordErrorTimer > 0) {
c.fill(255,70,70); c.text("ACCESS DENIED - RETRY",cx-88,cy-145)
} else {
c.fill(0,220,180); c.text("WAITING FOR AUTHORIZATION",cx-115,cy-145)
}
c.fill(100,150,190); c.text("TYPE: YADNESH SHA...",cx-92,cy+145)
c.fill(80,120,150); c.text("SPACE IS REQUIRED BETWEEN WORDS",cx-125,cy+120)
if (passwordSuccessPulse > 0) {
c.noFill(); c.stroke(0,255,180,(passwordSuccessPulse*230).toInt); c.strokeWeight(5)
c.rect(cx-290,cy-180,580,360); passwordSuccessPulse *= 0.90
}
}
// ============================================================
// AVATAR SELECTION - 4 CARDS -> ONLY SELECTED CARD
// ============================================================
def drawAvatarSelectionScreen(c: CanvasDraw): Unit = {
avatarFloat += 0.045
avatarButtonClockSafe()
c.background(2,6,20)
drawStarfield(c)
c.stroke(0,170,220,28); c.strokeWeight(1)
var gx = 0.0
while (gx < cwidth) { c.line(gx,0,gx,cheight); gx += 45 }
var gy = 0.0
while (gy < cheight) { c.line(0,gy,cwidth,gy); gy += 45 }
c.fill(0,255,230); c.text("DEFENSE COMMAND // AVATAR SELECTION",cwidth/2.0-175,cheight-30)
c.fill(255,215,60); c.text("SELECT YOUR SAINIK AVATAR",cwidth/2.0-125,cheight-58)
val cardW = 170.0
val cardH = 275.0
val firstX = cwidth/2.0-365.0
val cardY = cheight/2.0-145.0
if (!avatarLocked) {
c.fill(140,190,210); c.text("Choose one specialist - the other avatars will hide after selection.",cwidth/2.0-200,cheight-84)
var i = 0
while (i < 4) {
val x = firstX + i*185.0
val hovered = mouseX >= x && mouseX <= x+cardW && mouseY >= cardY && mouseY <= cardY+cardH
val selected = selectedAvatar == i+1
if (selected) { c.fill(0,65,85,245); c.stroke(0,255,255); c.strokeWeight(3.5) }
else if (hovered) { c.fill(20,45,70,245); c.stroke(255,215,70); c.strokeWeight(2.5) }
else { c.fill(7,20,40,235); c.stroke(55,90,120); c.strokeWeight(1.5) }
c.rect(x,cardY,cardW,cardH)
drawAvatar(c,x+cardW/2.0,cardY+105,i+1,0.9,selected,false)
c.fill(cm.rgb(255,255,255)); c.text(avatarNames(i),x+19,cardY+178)
c.fill(0,245,220); c.text(avatarRoles(i),x+26,cardY+200)
c.fill(160,190,210)
if (i == 0) { c.text("Balanced Combat",x+24,cardY+228); c.text("Tactical AI",x+43,cardY+248) }
else if (i == 1) { c.text("Heavy Armour",x+31,cardY+228); c.text("High Defense",x+42,cardY+248) }
else if (i == 2) { c.text("Rapid Movement",x+28,cardY+228); c.text("Recon Expert",x+38,cardY+248) }
else { c.text("Energy Control",x+28,cardY+228); c.text("Quantum Systems",x+20,cardY+248) }
if (isMousePressed && hovered) {
selectedAvatar = i+1
avatarLocked = true
avatarTransition = 1.0
avatarSelectFlash = 1.0
playFX(72+i*4,90)
}
i += 1
}
} else {
val centerX = cwidth/2.0
val centerY = cheight/2.0-10.0
avatarTransition *= 0.93
avatarSelectFlash *= 0.90
c.fill(0,55,80,245); c.stroke(0,255,255); c.strokeWeight(4); c.rect(centerX-135,centerY-155,270,315)
c.noFill(); c.stroke(0,255,255,130); c.strokeWeight(2.5)
c.ellipse(centerX,centerY-15,235+math.sin(avatarFloat*3.0)*10,280)
c.stroke(255,215,60,90); c.ellipse(centerX,centerY-15,255+math.sin(avatarFloat*2.0)*12,300)
drawAvatar(c,centerX,centerY-30,selectedAvatar,1.28,true,false)
c.fill(cm.rgb(255,255,255)); c.text(avatarNames(selectedAvatar-1),centerX-65,centerY+105)
c.fill(0,255,220); c.text(avatarRoles(selectedAvatar-1),centerX-58,centerY+130)
c.fill(255,215,60); c.text("AVATAR SELECTED",centerX-62,centerY+155)
c.fill(130,210,230); c.text("3 OTHER AVATARS HIDDEN",centerX-95,centerY-190)
if (avatarSelectFlash > 0.01) { c.noFill(); c.stroke(255,255,255,(avatarSelectFlash*230).toInt); c.strokeWeight(8); c.ellipse(centerX,centerY-15,270+avatarSelectFlash*90,320+avatarSelectFlash*100) }
}
c.fill(100,255,225); c.text("SELECTED: "+avatarNames(selectedAvatar-1),cwidth/2.0-112,104)
val bx = cwidth/2.0-140
val by = 42.0
c.fill(if (avatarLocked) 0 else 55,if (avatarLocked) 150 else 70,if (avatarLocked) 95 else 85)
c.stroke(0,255,180); c.strokeWeight(2.5); c.rect(bx,by,280,48)
c.fill(cm.rgb(255,255,255)); c.text(if (avatarLocked) "START MISSION" else "SELECT AVATAR FIRST",bx+62,by+30)
if (isMousePressed && avatarLocked && mouseX >= bx && mouseX <= bx+280 && mouseY >= by && mouseY <= by+48) {
currentGameState = 0
briefingIndex = 0
briefingTimer = 0.0
squadDeploy = 0.0
playFX(84,180)
}
}
def avatarButtonClockSafe(): Unit = { }
// ============================================================
// BRIEFING
// ============================================================
def drawBriefing(c: CanvasDraw): Unit = {
c.background(1,4,16); drawStarfield(c)
c.fill(8,16,40,250); c.stroke(0,255,255); c.strokeWeight(3)
val bx = cwidth/2.0-315; val by = cheight/2.0-190
c.rect(bx,by,630,400)
c.fill(255,215,60); c.text("OPERATION SINDOOR // COMMAND BRIEFING",bx+30,by+32)
c.fill(80,255,225); c.text(ENGINE_VERSION,bx+440,by+32)
val shown = briefingText.substring(0,briefingIndex)
val lines = shown.split("\n")
var ty = by+68
for (line <- lines) { c.fill(230,240,255); c.text(line,bx+25,ty); ty += 19 }
if (briefingIndex >= briefingText.length) {
val sx = bx+170; val sy = by-58
c.fill(0,220,150); c.stroke(cm.rgb(255,255,255)); c.strokeWeight(2); c.rect(sx,sy,290,44)
c.fill(cm.rgb(255,255,255)); c.text("INITIALIZE MISSION",sx+63,sy+28)
if (isMousePressed && mouseX>=sx && mouseX<=sx+290 && mouseY>=sy && mouseY<=sy+44) {
currentGameState = 1; squadDeploy = 0.0; playFX(80,150)
}
}
}
// ============================================================
// COMBAT BACKGROUND
// ============================================================
def drawCombatBackground(c: CanvasDraw): Unit = {
c.background(2,5,20); drawStarfield(c)
c.fill(15,50,150,25); c.noStroke(); c.ellipse(cwidth/2,100,cwidth+100,160)
c.stroke(0,120,160,35); c.strokeWeight(1)
var y = 80.0
while (y < 260) { c.line(0,y,cwidth,y); y += 25 }
var x = 0.0
while (x < cwidth) { c.line(x,120,cwidth/2,80); x += 50 }
c.noFill(); c.stroke(0,220,255,35); c.strokeWeight(2)
c.ellipse(cwidth/2,180,480+math.sin(gridPulse)*25,260)
}
// ============================================================
// TANK
// ============================================================
def drawTank(c: CanvasDraw): Unit = {
c.fill(0,0,0,120); c.noStroke(); c.ellipse(tankX,tankY-4,175,24)
c.fill(34,39,44); c.stroke(12,17,22); c.strokeWeight(1.5); c.rect(tankX-70,tankY,140,32)
c.fill(100,105,101)
for (i <- -5 to 5) c.ellipse(tankX+i*13.5,tankY+16,11,11)
c.fill(68,110,60); c.rect(tankX-55,tankY+30,110,30)
c.fill(58,96,52); c.ellipse(tankX,tankY+59,60,34)
val barrel = 90+tankRecoil*4
val tx = tankX+math.cos(turretAngle)*barrel
val ty = tankY+59+math.sin(turretAngle)*barrel
c.stroke(42,72,37); c.strokeWeight(10+tankRecoil*2); c.line(tankX,tankY+59,tx,ty)
val enginePulse = 70+(math.abs(math.sin(tankEngine))*150).toInt
c.fill(255,80,20,enginePulse); c.noStroke(); c.ellipse(tankX-50,tankY+4,8,5); c.ellipse(tankX+50,tankY+4,8,5)
if (cannonFlash > 0) { c.fill(255,150,40,220); c.ellipse(tx,ty,50,50); c.fill(255,250,180,240); c.ellipse(tx,ty,22,22) }
}
// ============================================================
// SILO
// ============================================================
def drawSilo(c: CanvasDraw): Unit = {
c.fill(58,63,73); c.stroke(25,30,38); c.strokeWeight(2); c.ellipse(siloX,siloY,76,76)
c.pushMatrix(); c.translate(siloX,siloY); c.rotate(siloAngle); c.fill(82,108,94); c.rect(-18,-21,80,42); c.popMatrix()
}
// ============================================================
// AIR DEFENSE
// ============================================================
def drawAirDefense(c: CanvasDraw): Unit = {
c.fill(45,85,60); c.stroke(20,45,30); c.strokeWeight(2); c.rect(akashX-36,akashY-16,72,32)
c.pushMatrix(); c.translate(akashX,akashY); c.rotate(akashAngle); c.stroke(0,255,180,170); c.strokeWeight(2); c.line(0,0,25,0); c.popMatrix()
c.fill(0,255,180); c.noStroke(); c.ellipse(akashX,akashY,15,15); c.fill(cm.rgb(255,255,255)); c.text("AKASH",akashX-22,akashY-24)
c.fill(85,65,43); c.stroke(45,30,18); c.strokeWeight(2); c.rect(pinakaX-42,pinakaY-20,84,40)
c.fill(255,153,51,(70+(math.abs(math.sin(pinakaPulse))*160)).toInt); c.noStroke(); c.ellipse(pinakaX-17,pinakaY,9,9); c.ellipse(pinakaX,pinakaY,9,9); c.ellipse(pinakaX+17,pinakaY,9,9)
c.fill(cm.rgb(255,255,255)); c.text("PINAKA",pinakaX-26,pinakaY-28)
}
// ============================================================
// SQUAD
// ============================================================
def drawSquad(c: CanvasDraw): Unit = {
var i = 0
while (i < squadCount) {
val offset = (i-1.5)*75
val x = cwidth/2+offset
val y = 140+math.sin(squadMarch+i.toDouble)*2.5
drawAvatar(c,x,y,selectedAvatar,0.9*math.max(0.2,squadDeploy),false,squadSalute>0.5)
i += 1
}
}
// ============================================================
// COMMAND DRONE
// ============================================================
def drawCommandDrone(c: CanvasDraw): Unit = {
val x = cwidth/2+math.cos(squadDrone)*220
val y = 250+math.sin(squadDrone*1.7)*30
c.fill(40,50,60); c.stroke(0,220,255); c.strokeWeight(2); c.ellipse(x,y,38,18)
c.fill(0,230,255); c.noStroke(); c.ellipse(x,y,10,10)
c.stroke(180,240,255,150); c.strokeWeight(2); c.line(x-20,y,x-42,y); c.line(x+20,y,x+42,y)
}
// ============================================================
// RADAR
// ============================================================
def drawRadar(c: CanvasDraw): Unit = {
val x = 80.0; val y = cheight-120.0
c.fill(5,20,30,230); c.stroke(0,255,160,200); c.strokeWeight(2)
c.ellipse(x,y,120,120); c.ellipse(x,y,82,82); c.ellipse(x,y,42,42)
c.line(x-60,y,x+60,y); c.line(x,y-60,x,y+60)
c.stroke(0,255,180); c.strokeWeight(2.5); c.line(x,y,x+math.cos(universalClock)*56,y+math.sin(universalClock)*56)
repeatFor(enemies) { e =>
if (!e.destroyed) {
val dx = math.max(-50,math.min(50,(e.x-cwidth/2)/5))
val dy = math.max(-50,math.min(50,(e.y-cheight/2)/5))
c.fill(255,50,60); c.noStroke(); c.ellipse(x+dx,y+dy,5,5)
}
}
}
// ============================================================
// HUD
// ============================================================
def drawHUD(c: CanvasDraw): Unit = {
c.fill(5,10,30,245); c.stroke(0,255,255,190); c.strokeWeight(2); c.rect(15,cheight-66,cwidth-30,50)
c.fill(255,220,70); c.text("OPERATION SINDOOR",28,cheight-38)
c.fill(100,255,225); c.text(s"TARGETS: $scoreDestroyedCount / $quotaRequirement",210,cheight-38)
c.fill(255,120,110); c.text(s"TIME: ${combatTimer.toInt}s",390,cheight-38)
c.fill(30,35,48); c.rect(500,cheight-53,170,10)
c.fill(40,220,110); c.rect(500,cheight-53,170*math.max(0,math.min(1,commanderHP/100)),10)
c.fill(cm.rgb(255,255,255)); c.text("COMMANDER HP",545,cheight-25)
drawRadar(c)
}
// ============================================================
// CONTROLS
// ============================================================
def drawControls(c: CanvasDraw): Unit = {
c.fill(14,20,45,255); c.stroke(0,255,255); c.strokeWeight(1.8); c.rect(15,88,710,52)
val labs = Array("T-","T+","C-","C+","FIRE","M-","M+","A","B","C","LAUNCH")
val xs = Array(20.0,78.0,136.0,194.0,252.0,320.0,374.0,426.0,480.0,534.0,592.0)
val ws = Array(52.0,52.0,52.0,52.0,62.0,48.0,48.0,48.0,48.0,48.0,120.0)
var i = 0
while (i < labs.length) {
if (i == 4) c.fill(240,100,0)
else if (i >= 7 && i <= 9) c.fill(if (missileType == i-6) 240 else 80,35,150)
else if (i == 10) c.fill(200,0,240)
else c.fill(70,75,110)
c.rect(xs(i),96,ws(i),32); c.fill(cm.rgb(255,255,255)); c.text(labs(i),xs(i)+18,116); i += 1
}
}
// ============================================================
// PRIMARY COMMAND PANEL - 4 CLEAR COMMANDS
// ============================================================
def drawPrimaryCommands(c: CanvasDraw): Unit = {
val y = cheight - 142.0
val h = 40.0
val gap = 10.0
val start = 168.0
val w = 124.0
val labels = Array("MOVE", "AIM", "FIRE", "MISSILE")
val keys = Array("LEFT / RIGHT", "UP / DOWN", "SPACE", "ENTER")
c.fill(5, 14, 34, 235)
c.stroke(0, 220, 255, 150)
c.strokeWeight(1.5)
c.rect(start - 10, y - 8, 4 * w + 3 * gap + 20, h + 18)
var i = 0
while (i < 4) {
val x = start + i * (w + gap)
if (i == 3 && missileLaunchPulse > 0.05) {
c.fill(245, 90, 20)
c.stroke(255, 220, 90)
c.strokeWeight(2.5)
} else if (i == 2) {
c.fill(170, 72, 20)
c.stroke(255, 170, 80)
c.strokeWeight(1.5)
} else {
c.fill(24, 46, 78)
c.stroke(0, 210, 255, 160)
c.strokeWeight(1.5)
}
c.rect(x, y, w, h)
c.fill(cm.rgb(255,255,255))
c.text(labels(i), x + 40, y + 18)
c.fill(160, 205, 225)
c.text(keys(i), x + 20, y + 33)
i += 1
}
}
def handlePrimaryCommands(): Unit = {
if (currentGameState != 2 && currentGameState != 3) return
if (!isMousePressed) return
val y = cheight - 142.0
val h = 40.0
val gap = 10.0
val start = 168.0
val w = 124.0
if (mouseY >= y && mouseY <= y + h) {
if (mouseX >= start && mouseX <= start + w) {
tankX -= 10.0
} else if (mouseX >= start + (w + gap) && mouseX <= start + (w + gap) + w) {
turretAngle += 0.10
} else if (mouseX >= start + 2*(w + gap) && mouseX <= start + 2*(w + gap) + w) {
fireGun()
} else if (mouseX >= start + 3*(w + gap) && mouseX <= start + 3*(w + gap) + w) {
fireMissile()
}
}
}
// ============================================================
// BOSS
// ============================================================
def drawBoss(c: CanvasDraw): Unit = {
if (!bossActive) return
if (bossShield > 0) { c.noFill(); c.stroke(0,220,255,140); c.strokeWeight(5); c.ellipse(bossX,bossY,165+math.sin(bossCore)*10,100+math.sin(bossCore)*8) }
c.fill(125,20,30); c.stroke(255,190,50); c.strokeWeight(3); c.ellipse(bossX,bossY,125,64)
c.fill(60,65,80); c.rect(bossX-42,bossY-40,84,24)
val pulse = 20+math.abs(math.sin(bossCore))*7
c.fill(255,50,40,150); c.noStroke(); c.ellipse(bossX,bossY,pulse+12,pulse+12)
c.fill(255,50,40); c.ellipse(bossX,bossY,pulse,pulse)
c.fill(20,20,28); c.rect(bossX-85,bossY+58,170,10)
val hpRatio = math.max(0,math.min(1,bossHP/bossMaxHP))
c.fill(255,45,45); c.rect(bossX-85,bossY+58,170*hpRatio,10)
if (bossShield > 0) { c.fill(0,210,255); c.rect(bossX-85,bossY+72,170*math.max(0,math.min(1,bossShield/100)),5) }
c.fill(255,220,80); c.text(s"PHASE $bossPhase",bossX-32,bossY+95)
}
// ============================================================
// TARGET LOCK / SCAN
// ============================================================
def drawTargetLock(c: CanvasDraw): Unit = {
if (enemies.nonEmpty) {
val t = enemies.head
if (!t.destroyed) {
val px = t.x; val py = t.y
c.noFill(); c.stroke(0,255,220,200); c.strokeWeight(2)
c.line(px-32,py-24,px-10,py-24); c.line(px+10,py-24,px+32,py-24)
c.line(px-32,py+24,px-10,py+24); c.line(px+10,py+24,px+32,py+24)
c.fill(0,255,220); c.noStroke(); c.text("TARGET",px-22,py+42)
}
}
}
def drawSainikScan(c: CanvasDraw): Unit = {
val cx = cwidth/2.0; val cy = 185.0
c.noFill(); c.stroke(0,255,220,70); c.strokeWeight(2)
c.ellipse(cx,cy,350+math.sin(squadScan)*20,170)
c.stroke(0,230,255,100)
c.line(cx,cy,cx+math.cos(squadScan)*290,cy+math.sin(squadScan)*110)
}
// ============================================================
// COMBAT
// ============================================================
def drawCombat(c: CanvasDraw): Unit = {
drawCombatBackground(c)
drawSainikScan(c)
drawSquad(c)
drawCommandDrone(c)
drawTank(c)
drawSilo(c)
drawAirDefense(c)
drawParticles(c)
repeatFor(shells)(_.draw(c))
repeatFor(missiles)(_.draw(c))
repeatFor(enemies)(_.draw(c))
repeatFor(shockwaves)(_.draw(c))
drawTargetLock(c)
drawBoss(c)
drawControls(c)
drawPrimaryCommands(c)
drawHUD(c)
c.fill(150,195,220)
c.text("KEYS: LEFT / RIGHT MOVE | UP / DOWN AIM | SPACE FIRE | ENTER MISSILE",168,cheight-90)
if (bossActive) { c.fill(255,60,60); c.text("FLAGSHIP BATTLE ACTIVE",cwidth/2-95,cheight-35) }
}
// ============================================================
// FIRE
// ============================================================
def fireGun(): Unit = {
if (cannonCooldown <= 0) {
val mx = tankX+math.cos(turretAngle)*94
val my = tankY+59+math.sin(turretAngle)*94
shells.append(new Shell(mx,my,math.cos(turretAngle)*14,math.sin(turretAngle)*14))
cannonCooldown = 8; cannonFlash = 6; tankRecoil = 3.5; tankHeat += 10
spawnParticles(mx,my,255,180,60,8); screenShake = 4; playFX(72,40)
}
}
def playMissileLaunchFX(): Unit = {
// Four-stage launch/boost sound: ignition -> whoosh -> boost -> lock.
playFX(48, 30)
playFX(60, 30)
playFX(72, 40)
playFX(84, 55)
}
def fireMissile(): Unit = {
if (missileCooldown <= 0) {
val speed = if (missileType == 2) 8.0 else if (missileType == 3) 11.0 else 9.0
val mx = siloX+math.cos(siloAngle)*65
val my = siloY+math.sin(siloAngle)*65
missiles.append(new Missile(mx,my,speed,siloAngle,missileType))
missileCooldown = 12
missileLaunchPulse = 1.0
missileLaunchSoundCooldown = 10
spawnParticles(mx,my,255,140,40,18)
spawnParticles(mx,my,255,235,120,6)
screenShake = 3
playMissileLaunchFX()
}
}
// ============================================================
// CONTROLS
// ============================================================
def handleMouseControls(): Unit = {
if (currentGameState != 2 && currentGameState != 3) return
if (!isMousePressed) return
val mx = mouseX; val my = mouseY
if (mx >= 20 && mx <= 70 && my >= 90 && my <= 125) tankX -= 6
else if (mx >= 75 && mx <= 125 && my >= 90 && my <= 125) tankX += 6
else if (mx >= 130 && mx <= 180 && my >= 90 && my <= 125) turretAngle -= 0.06
else if (mx >= 185 && mx <= 235 && my >= 90 && my <= 125) turretAngle += 0.06
else if (mx >= 240 && mx <= 315 && my >= 90 && my <= 125) fireGun()
else if (mx >= 320 && mx <= 365 && my >= 90 && my <= 125) siloAngle -= 0.06
else if (mx >= 370 && mx <= 415 && my >= 90 && my <= 125) siloAngle += 0.06
else if (mx >= 420 && mx <= 465 && my >= 90 && my <= 125) missileType = 1
else if (mx >= 470 && mx <= 515 && my >= 90 && my <= 125) missileType = 2
else if (mx >= 520 && mx <= 565 && my >= 90 && my <= 125) missileType = 3
else if (mx >= 570 && mx <= 700 && my >= 90 && my <= 125) fireMissile()
}
def handleKeyboard(): Unit = {
if (currentGameState != 2 && currentGameState != 3) return
if (isKeyPressed(Kc.VK_LEFT)) tankX -= 3.5
if (isKeyPressed(Kc.VK_RIGHT)) tankX += 3.5
if (isKeyPressed(Kc.VK_UP)) turretAngle += 0.045
if (isKeyPressed(Kc.VK_DOWN)) turretAngle -= 0.045
if (isKeyPressed(Kc.VK_SPACE)) fireGun()
if (isKeyPressed(Kc.VK_1)) missileType = 1
if (isKeyPressed(Kc.VK_2)) missileType = 2
if (isKeyPressed(Kc.VK_3)) missileType = 3
if (isKeyPressed(Kc.VK_ENTER)) fireMissile()
}
// ============================================================
// COLLISIONS / WORLD
// ============================================================
def checkCollisions(): Unit = {
repeatFor(enemies) { enemy =>
if (!enemy.destroyed) {
repeatFor(shells) { shell =>
if (shell.active && math.abs(shell.x-enemy.x)<40 && math.abs(shell.y-enemy.y)<40) {
shell.active=false; enemy.destroyed=true; scoreDestroyedCount+=1; explosion(enemy.x,enemy.y,25)
}
}
repeatFor(missiles) { missile =>
if (missile.active && math.abs(missile.x-enemy.x)<46 && math.abs(missile.y-enemy.y)<46) {
missile.active=false; enemy.destroyed=true; scoreDestroyedCount+=1; explosion(enemy.x,enemy.y,30)
}
}
}
}
if (bossActive) {
repeatFor(shells) { shell =>
if (shell.active && math.abs(shell.x-bossX)<75 && math.abs(shell.y-bossY)<65) {
shell.active=false
if (bossShield > 0) bossShield -= 8 else bossHP -= 18
explosion(shell.x,shell.y,28)
}
}
repeatFor(missiles) { missile =>
if (missile.active && math.abs(missile.x-bossX)<78 && math.abs(missile.y-bossY)<68) {
missile.active=false
if (bossShield > 0) bossShield -= 18 else bossHP -= 38
explosion(missile.x,missile.y,32)
}
}
if (bossShield < 0) bossShield = 0
}
}
def updateObjects(): Unit = {
shells.filterInPlace(_.active); repeatFor(shells)(_.update())
missiles.filterInPlace(_.active); repeatFor(missiles)(_.update())
enemies.filterInPlace(_.active); repeatFor(enemies)(_.update())
shockwaves.filterInPlace(_.life > 0); repeatFor(shockwaves)(_.update())
}
def spawnEnemy(): Unit = {
if (enemies.length >= MAX_ENEMIES) return
val x = randomDouble(80,cwidth-80)
val pattern = random(1,5)
val speed = -(0.7+randomDouble(0,0.65))
enemies.append(new Enemy(x,cheight+40,speed,pattern))
spawnParticles(x,cheight-10,255,50,50,7)
}
def startBoss(): Unit = {
bossActive=true; bossHP=bossMaxHP; bossShield=100; bossPhase=1; bossMovement=0; currentGameState=3
redAlert=1; screenShake=10; cinematicBars=8; playFX(42,220)
}
// ============================================================
// FINAL STRIKE / VICTORY
// ============================================================
def drawFinalStrike(c: CanvasDraw): Unit = {
if (currentGameState != 4) return
c.pushMatrix(); c.translate(strikeX,strikeY); c.rotate(strikeAngle)
c.fill(255,80,20,60); c.noStroke(); c.ellipse(-25,0,80,40)
c.fill(245,245,245); c.stroke(150,30,30); c.strokeWeight(2); c.rect(-38,-12,76,24)
c.fill(255,235,100); c.noStroke(); c.ellipse(40,0,28,28)
c.popMatrix()
}
def drawVictory(c: CanvasDraw): Unit = {
c.background(0,0,0); drawStarfield(c)
c.fill(255,153,51); c.rect(cwidth/2-220,70,440,5)
c.fill(cm.rgb(255,255,255)); c.rect(cwidth/2-220,61,440,5)
c.fill(18,136,7); c.rect(cwidth/2-220,52,440,5)
c.fill(255,220,100); c.text("JAI HIND",cwidth/2-40,cheight/2+110)
c.fill(cm.rgb(255,255,255)); c.text("MISSION COMPLISHED",cwidth/2-135,cheight/2+55)
c.fill(255,235,190); c.text("SAINIK COMMAND SUCCEEDED",cwidth/2-125,cheight/2+20)
c.fill(100,240,255); c.text("QUANTUM DEFENSE STATUS: STABLE",cwidth/2-135,cheight/2-15)
c.fill(cm.rgb(255,255,255)); c.text("SELECTED AVATAR:",cwidth/2-110,cheight/2-55)
c.fill(0,255,190); c.text(avatarNames(selectedAvatar-1),cwidth/2-95,cheight/2-78)
c.fill(255,220,80); c.text(s"DEFENSE SCORE: $scoreDestroyedCount",cwidth/2-85,cheight/2-110)
drawAvatar(c,cwidth/2,cheight/2-180,selectedAvatar,1.35,false,true)
}
// ============================================================
// DEPLOYMENT
// ============================================================
def drawDeployment(c: CanvasDraw): Unit = {
drawCombatBackground(c)
val p = math.max(0.2,math.min(1,squadDeploy))
var i=0
while(i<squadCount){
val offset=(i-1.5)*75; val sx=cwidth/2+offset; val sy=140+math.sin(squadMarch+i*0.8)*3
drawAvatar(c,sx,sy,selectedAvatar,p,false,true); i+=1
}
drawTank(c); drawSilo(c); drawAirDefense(c)
c.fill(255,215,60); c.text("SAINIK SQUAD DEPLOYMENT",cwidth/2-115,cheight-35)
c.fill(100,255,225); c.text("FORMATION ALPHA // ALL UNITS READY",cwidth/2-135,cheight-60)
}
// ============================================================
// UPDATE WORLD
// ============================================================
def updateWorld(): Unit = {
universalClock += 0.025
avatarFloat += 0.035
commanderPulse += 0.06
tankEngine += 0.08
squadMarch += 0.14
squadScan += 0.04
squadDrone += 0.025
akashAngle += 0.035
pinakaPulse += 0.07
bossCore += 0.09
scanPulse += 0.05
gridPulse += 0.08
screenShake *= 0.86
colorFlash *= 0.84
redAlert *= 0.95
cinematicBars *= 0.97
tankRecoil *= 0.85
tankHeat *= 0.99
missileLaunchPulse *= 0.88
if (missileLaunchSoundCooldown > 0) missileLaunchSoundCooldown -= 1
if (cannonFlash>0) cannonFlash-=1
if (cannonCooldown>0) cannonCooldown-=1
if (missileCooldown>0) missileCooldown-=1
updateParticles()
if (!passwordUnlocked) { updatePassword(); return }
if (currentGameState == 0) {
briefingTimer += 0.04
if (briefingTimer >= 0.025 && briefingIndex < briefingText.length) { briefingIndex+=1; briefingTimer=0 }
return
}
if (currentGameState == 1) {
squadDeploy=math.min(1,squadDeploy+0.018)
squadSalute=0.5+math.sin(universalClock)*0.5
if (squadDeploy>=1) { currentGameState=2; playFX(82,140) }
return
}
if (currentGameState == 2) {
handlePrimaryCommands(); handleMouseControls(); handleKeyboard(); combatTimer -= 0.033; updateObjects(); checkCollisions()
tankX=math.max(60,math.min(cwidth-60,tankX))
if (randomDouble(0,1)<0.055) spawnEnemy()
if (pinakaCooldown<=0 && enemies.nonEmpty) {
val target=enemies.head; val angle=math.atan2(target.y-pinakaY,target.x-pinakaX)
missiles.append(new Missile(pinakaX,pinakaY,10.5,angle,3)); pinakaCooldown=38; playFX(68,30)
} else pinakaCooldown-=1
if (combatTimer<=45 && !bossActive) { startBoss(); return }
return
}
if (currentGameState == 3) {
handlePrimaryCommands(); handleMouseControls(); handleKeyboard(); updateObjects(); checkCollisions(); bossMovement+=0.035
bossX=cwidth/2+math.sin(bossMovement*1.8)*225
if (bossPhase==1 && bossHP<500) { bossPhase=2; redAlert=1; screenShake=8; playFX(48,140) }
if (bossPhase==2 && bossHP<230) { bossPhase=3; redAlert=1; screenShake=11; playFX(38,160) }
if (randomDouble(0,1)<0.20) spawnParticles(bossX+randomDouble(-50,50),bossY+randomDouble(-30,30),255,50,40,2)
if (bossHP<=0) {
bossActive=false; currentGameState=4; strikeX=tankX+260; strikeY=cheight+160; strikeSpeed=8.5; cinematicBars=12
megaExplosion(bossX,bossY); playFX(36,250)
}
return
}
if (currentGameState == 4) {
val dx=tankX-strikeX; val dy=(tankY+50)-strikeY
val targetAngle=math.atan2(dy,dx)
strikeAngle += (targetAngle-strikeAngle)*0.08
strikeX += math.cos(strikeAngle)*strikeSpeed
strikeY += math.sin(strikeAngle)*strikeSpeed
strikeSpeed += 0.06
if (math.abs(strikeX-tankX)<30 && math.abs(strikeY-(tankY+50))<30) {
megaExplosion(tankX,tankY+50); currentGameState=5; playFX(36,300)
}
updateObjects(); return
}
if (currentGameState == 5) { updateObjects(); return }
}
// ============================================================
// RENDER
// ============================================================
def renderGame(c: CanvasDraw): Unit = {
if (currentGameState == -1) { drawPasswordScreen(c); return }
if (currentGameState == -2) { drawAvatarSelectionScreen(c); return }
if (currentGameState == 0) { drawBriefing(c); return }
if (currentGameState == 1) { drawDeployment(c); return }
if (currentGameState == 5) { drawVictory(c); return }
if (screenShake > 0.5) {
c.pushMatrix(); c.translate(randomDouble(-screenShake,screenShake),randomDouble(-screenShake,screenShake))
}
drawCombat(c)
if (currentGameState == 4) drawFinalStrike(c)
if (screenShake > 0.5) c.popMatrix()
if (colorFlash > 0.01) {
c.fill(255,245,210,math.max(0,math.min(255,(colorFlash*255).toInt))); c.noStroke(); c.rect(0,0,cwidth,cheight)
}
if (redAlert > 0.02) {
c.noFill(); c.stroke(255,20,20,math.min(190,(redAlert*190).toInt)); c.strokeWeight(6); c.rect(4,4,cwidth-8,cheight-8)
}
val bars=math.max(0,math.min(55,cinematicBars.toInt))
if (bars>0) { c.fill(cm.rgb(0,0,0)); c.noStroke(); c.rect(0,0,cwidth,bars); c.rect(0,cheight-bars,cwidth,bars) }
}
// ============================================================
// MAIN LOOP
// ============================================================
animateWithCanvasDraw { c =>
updateWorld()
renderGame(c)
}