Code Sketch
bhavesh shahare
Category: Programming
// --- OPERATION SINDOOR PART 2: THE BORDER WAR ---
cleari()
originBottomLeft()
// --- GAME STATES ---
// 0: Intro Part 2, 1: Confidential Letter, 2: Cutscene (Hatch Enter), 3: Gameplay, 4: Victory, 5: Defeat
var gameState = 0
var letterTimer = 0 // ???????? ??? ????????????? ?????
// --- CUTSCENE VARIABLES ---
var cutsceneTankX = cwidth + 120.0
var heroX = -50.0
var cutscenePhase = 1
var hatchOpen = false
var heroInside = false
// --- GAMEPLAY & TIMER VARIABLES ---
var timer = 50.0 // 50 Seconds Countdown
val targetKills = 12
var interceptedCount = 0
var baseHealth = 100
val gravity = Vector2D(0, -0.08)
var waveAngle = 0.0
var chakraRotation = 0.0
// Player Tank & Launcher
var playerTankX = cwidth / 2.0
val playerTankY = 30.0
var playerCannonAngle = math.Pi / 2.0
var muzzleFlashTimer = 0
var missileX = 120.0
var missileY = 150.0
var missileAngle = math.Pi / 2.0
var selectedMissileType = 1
// --- AUTO-BOT ALLY TANKS ---
class AllyTank(val x: Double, val y: Double) {
var cannonAngle = math.Pi / 2.0
var fireTimer = random(30, 80)
def step(targets: ArrayBuffer[EnemyMissile], shells: ArrayBuffer[TankShell]) {
fireTimer -= 1
var nearest: EnemyMissile = null
var minDist = 9999.0
repeatFor(targets) { em =>
val d = math.hypot(em.x - x, em.y - y)
if (d < minDist && em.y > y) {
minDist = d
nearest = em
}
}
if (nearest != null) {
val dx = nearest.x - x
val dy = nearest.y - y
cannonAngle = math.atan2(dy, dx)
}
if (fireTimer <= 0 && nearest != null) {
val tx = x + math.cos(cannonAngle) * 50.0
val ty = y + math.sin(cannonAngle) * 50.0
shells.append(new TankShell(tx, ty, math.cos(cannonAngle) * 9.0, math.sin(cannonAngle) * 9.0, true))
fireTimer = random(40, 90)
}
}
def view(canvas: CanvasDraw) {
canvas.fill(40, 50, 40); canvas.stroke(10, 20, 10); canvas.strokeWeight(1)
canvas.rect(x - 35, y, 70, 16)
canvas.fill(60, 75, 55); canvas.rect(x - 28, y + 16, 56, 14)
canvas.fill(45, 60, 40); canvas.ellipse(x, y + 30, 32, 18)
canvas.stroke(30, 45, 25); canvas.strokeWeight(6)
canvas.line(x, y + 30, x + math.cos(cannonAngle) * 45.0, y + math.sin(cannonAngle) * 45.0)
}
}
val allyTanks = ArrayBuffer(new AllyTank(150, 30), new AllyTank(cwidth - 150, 30), new AllyTank(cwidth - 320, 30))
// --- BLAST PARTICLES ---
class BlastParticle(x0: Double, y0: Double, r: Int, g: Int, b: Int) {
var loc = Vector2D(x0, y0)
var vel = Vector2D(randomDouble(-5, 5), randomDouble(-5, 5))
var life = 255.0
def step() { loc = loc + vel; life -= 12.0 }
def view(canvas: CanvasDraw) {
if (life > 0) {
canvas.noStroke()
canvas.fill(r, g, b, life.toInt)
canvas.ellipse(loc.x, loc.y, 8, 8)
}
}
}
val blastParticles = ArrayBuffer.empty[BlastParticle]
// --- INDIAN MISSILES ---
class StrategicMissile(var x: Double, var y: Double, val vx: Double, val vy: Double, var angle: Double, val mType: Int) {
var active = true
var trail = ArrayBuffer.empty[Vector2D]
def step() {
if (mType == 2) angle += 0.004
else if (mType == 3) angle += math.sin(x * 0.05) * 0.02
val speed = math.sqrt(vx*vx + vy*vy)
x += math.cos(angle) * speed
y += math.sin(angle) * speed
trail.append(Vector2D(x, y))
if (trail.length > 18) trail.remove(0)
if (x < -100 || x > cwidth + 100 || y < -100 || y > cheight + 100) active = false
}
def view(canvas: CanvasDraw) {
canvas.noStroke()
for (i <- 0 until trail.length) {
val alpha = ((i.toDouble / trail.length) * 150).toInt
canvas.fill(255, 120, 0, alpha)
canvas.ellipse(trail(i).x, trail(i).y, 8, 8)
}
canvas.pushMatrix()
canvas.translate(x, y); canvas.rotate(angle)
if (mType == 1) { // BRAHMOS
canvas.fill(220, 220, 230); canvas.stroke(40, 40, 50); canvas.strokeWeight(1); canvas.rect(-20, -7, 40, 14)
canvas.fill(200, 20, 20); canvas.noStroke(); canvas.ellipse(20, 0, 14, 14)
} else if (mType == 2) { // AGNI
canvas.fill(50, 55, 65); canvas.stroke(20, 20, 20); canvas.rect(-25, -10, 50, 20)
canvas.fill(240, 150, 0); canvas.ellipse(25, 0, 16, 16)
} else { // SUDARSHAN
canvas.fill(20, 140, 200); canvas.stroke(10, 50, 90); canvas.rect(-18, -6, 36, 12)
canvas.fill(0, 255, 255); canvas.noStroke(); canvas.ellipse(18, 0, 12, 12)
}
canvas.fill(255, 180, 0, 230); canvas.noStroke(); canvas.ellipse(-26, 0, 14, 10)
canvas.popMatrix()
}
}
val strategicMissiles = ArrayBuffer.empty[StrategicMissile]
// --- TANK SHELLS ---
class TankShell(var x: Double, var y: Double, val vx: Double, val vy: Double, val isAlly: Boolean) {
var active = true
def step() {
x += vx; y += vy
if (x < -50 || x > cwidth + 50 || y < -50 || y > cheight + 50) active = false
}
def view(canvas: CanvasDraw) {
if (isAlly) canvas.fill(0, 230, 255) else canvas.fill(255, 140, 0)
canvas.noStroke(); canvas.ellipse(x, y, 9, 9)
}
}
val tankShells = ArrayBuffer.empty[TankShell]
// --- PAKISTAN MISSILES ---
class EnemyMissile(var x: Double, var y: Double, var vy: Double, val mName: String) {
var active = true
var exploded = false
var explosionTimer = 0
def step() {
if (!exploded) {
y += vy
if (y < 15) { active = false; baseHealth -= 12 }
} else {
explosionTimer += 1
if (explosionTimer > 25) active = false
}
}
def view(canvas: CanvasDraw) {
if (!exploded) {
canvas.pushMatrix()
canvas.translate(x, y); canvas.rotate(-math.Pi / 2)
canvas.fill(20, 90, 35); canvas.stroke(10, 40, 15); canvas.strokeWeight(1)
canvas.rect(-18, -7, 36, 14)
canvas.fill(250, 250, 250); canvas.noStroke(); canvas.ellipse(18, 0, 12, 12)
canvas.popMatrix()
canvas.fill(255, 80, 80); canvas.text(mName, x - 20, y + 18)
} else {
canvas.noStroke(); canvas.fill(255, 100, 0, 200)
canvas.ellipse(x, y, 50 + explosionTimer * 2, 50 + explosionTimer * 2)
}
}
}
val enemyMissiles = ArrayBuffer.empty[EnemyMissile]
var enemySpawnTimer = 0
// --- FIREWORKS ---
val tricolorPalette = Array(cm.rgb(255, 153, 51), cm.rgb(255, 255, 255), cm.rgb(18, 136, 7))
class Particle(x0: Double, y0: Double, col: Color, seed: Boolean) {
var location = Vector2D(x0, y0)
private var velocity = if (seed) Vector2D(0, random(6, 12)) else Vector2D(randomNormalDouble, randomNormalDouble) * randomDouble(2, 5)
private var acceleration = Vector2D(0, 0)
var lifespan = 255.0
private var exploded = false
def applyForce(force: Vector2D) { acceleration = acceleration + force }
def shouldExplode: Boolean = !exploded && lifespan <= 0
def checkExplode() { if (seed && velocity.y < 0) lifespan = 0 }
def isDead: Boolean = { if (seed) exploded else lifespan <= 0 }
def explode() { exploded = true }
def step() {
velocity = velocity + acceleration; location = location + velocity
if (!seed) { lifespan -= 4; velocity = velocity * 0.94 }
acceleration = Vector2D(0, 0); checkExplode()
}
def view(canvas: CanvasDraw) {
canvas.stroke(col); canvas.strokeWeight(if (seed) 5 else 2)
canvas.point(location.x, location.y)
}
}
class Firework() {
private val fireworkColor = tricolorPalette(random(tricolorPalette.length))
private val firework = new Particle(random(cwidth), 0, fireworkColor, true)
private val particles = ArrayBuffer.empty[Particle]
def done: Boolean = firework.isDead && particles.isEmpty
def step() {
particles.filterInPlace(p => !p.isDead)
if (!firework.isDead) {
firework.applyForce(gravity); firework.step()
if (firework.shouldExplode) {
repeat(80) { particles.append(new Particle(firework.location.x, firework.location.y, fireworkColor, false)) }
firework.explode()
}
}
repeatFor(particles) { p => p.applyForce(gravity); p.step() }
}
def view(canvas: CanvasDraw) {
firework.view(canvas); repeatFor(particles) { p => p.view(canvas) }
}
}
val fireworks = ArrayBuffer.empty[Firework]
// --- SOLDIER & TANK WITH HATCH ---
def drawArmyMan(canvas: CanvasDraw, x: Double, y: Double) {
canvas.pushMatrix(); canvas.translate(x, y)
canvas.fill(20, 20, 20); canvas.noStroke(); canvas.rect(-7, 0, 5, 8); canvas.rect(2, 0, 5, 8)
canvas.fill(40, 60, 30); canvas.rect(-7, 8, 6, 20); canvas.rect(1, 8, 6, 20)
canvas.fill(55, 80, 40); canvas.rect(-9, 28, 18, 22)
canvas.fill(220, 170, 130); canvas.ellipse(0, 56, 12, 14)
canvas.fill(30, 50, 20); canvas.ellipse(0, 60, 16, 10)
canvas.popMatrix()
}
def drawCutsceneTank(canvas: CanvasDraw, tx: Double, ty: Double) {
canvas.fill(30, 33, 38); canvas.stroke(10, 10, 12); canvas.strokeWeight(1)
canvas.rect(tx - 50, ty, 100, 22)
canvas.fill(70, 75, 70)
for (i <- -4 to 4) canvas.ellipse(tx + (i * 11), ty + 11, 9, 9)
canvas.fill(50, 80, 45); canvas.rect(tx - 40, ty + 22, 80, 20)
canvas.fill(40, 70, 35); canvas.ellipse(tx, ty + 44, 44, 24)
if (hatchOpen) {
canvas.fill(15, 15, 15); canvas.ellipse(tx, ty + 53, 20, 8)
canvas.fill(60, 60, 60); canvas.rect(tx + 8, ty + 50, 12, 12)
} else {
canvas.fill(25, 30, 25); canvas.ellipse(tx, ty + 53, 22, 8)
}
canvas.stroke(25, 50, 20); canvas.strokeWeight(8)
canvas.line(tx, ty + 44, tx - 60, ty + 44)
}
// --- CUTSCENE ANIMATION ---
def updateCutscene() {
val targetTankX = cwidth / 2.0 + 80.0
val targetHeroX = targetTankX - 5.0
if (cutscenePhase == 1) {
if (cutsceneTankX > targetTankX) cutsceneTankX -= 4.0
if (heroX < targetHeroX) heroX += 3.0
if (cutsceneTankX <= targetTankX && heroX >= targetHeroX) cutscenePhase = 2
} else if (cutscenePhase == 2) {
hatchOpen = true
cutscenePhase = 3
} else if (cutscenePhase == 3) {
heroInside = true
cutscenePhase = 4
} else if (cutscenePhase == 4) {
hatchOpen = false
cutscenePhase = 5
} else if (cutscenePhase == 5) {
cutsceneTankX -= 5.0
if (cutsceneTankX < -150) gameState = 3
}
}
// --- UPDATE GAME STATE ---
def updateState() {
if (gameState == 0) {
if (isMousePressed) {
gameState = 1
letterTimer = 60 // ? ???????? ??? ????
}
return
}
if (gameState == 1) {
if (letterTimer > 0) letterTimer -= 1
else if (isMousePressed) gameState = 2
return
}
if (gameState == 2) {
updateCutscene()
return
}
if (gameState == 4 || gameState == 5) {
fireworks.filterInPlace(f => !f.done)
if (randomDouble(1) < 0.15) fireworks.append(new Firework())
repeatFor(fireworks) { f => f.step() }
return
}
// GAMEPLAY
timer -= 0.03
if (timer <= 0) {
if (interceptedCount >= targetKills) gameState = 4 else gameState = 5
}
if (baseHealth <= 0) gameState = 5
waveAngle += 0.08; chakraRotation += 0.05
blastParticles.filterInPlace(_.life > 0); repeatFor(blastParticles)(_.step())
val dx = mouseX - playerTankX
val dy = mouseY - (playerTankY + 44.0)
playerCannonAngle = math.atan2(dy, dx)
if (isMousePressed && mouseY > 140) {
val tx = playerTankX + math.cos(playerCannonAngle) * 60.0
val ty = (playerTankY + 44.0) + math.sin(playerCannonAngle) * 60.0
tankShells.append(new TankShell(tx, ty, math.cos(playerCannonAngle) * 10.0, math.sin(playerCannonAngle) * 10.0, false))
muzzleFlashTimer = 6
}
if (muzzleFlashTimer > 0) muzzleFlashTimer -= 1
if (mouseX >= 400 && mouseX <= 445 && mouseY >= 90 && mouseY <= 130 && isMousePressed) selectedMissileType = 1
else if (mouseX >= 450 && mouseX <= 495 && mouseY >= 90 && mouseY <= 130 && isMousePressed) selectedMissileType = 2
else if (mouseX >= 500 && mouseX <= 545 && mouseY >= 90 && mouseY <= 130 && isMousePressed) selectedMissileType = 3
else if (mouseX >= 555 && mouseX <= 630 && mouseY >= 90 && mouseY <= 130 && isMousePressed) {
val mTipX = missileX + math.cos(missileAngle) * 50.0
val mTipY = missileY + math.sin(missileAngle) * 50.0
strategicMissiles.append(new StrategicMissile(mTipX, mTipY, math.cos(missileAngle) * 6.5, math.sin(missileAngle) * 6.5, missileAngle, selectedMissileType))
}
repeatFor(allyTanks) { at => at.step(enemyMissiles, tankShells) }
enemySpawnTimer += 1
if (enemySpawnTimer >= 60) {
enemySpawnTimer = 0
val names = Array("PAKF-16", "BABUR", "SHAHEEN-3")
enemyMissiles.append(new EnemyMissile(random(100, cwidth - 100), cheight + 20.0, -1.3, names(random(names.length))))
}
tankShells.filterInPlace(_.active); repeatFor(tankShells)(_.step())
strategicMissiles.filterInPlace(_.active); repeatFor(strategicMissiles)(_.step())
enemyMissiles.filterInPlace(_.active); repeatFor(enemyMissiles)(_.step())
repeatFor(enemyMissiles) { em =>
if (!em.exploded) {
repeatFor(tankShells) { ts =>
if (ts.active && math.abs(ts.x - em.x) < 25 && math.abs(ts.y - em.y) < 25) {
em.exploded = true; ts.active = false
interceptedCount += 1
for (i <- 0 until 15) blastParticles.append(new BlastParticle(em.x, em.y, 255, 140, 0))
}
}
repeatFor(strategicMissiles) { sm =>
if (sm.active && math.abs(sm.x - em.x) < 35 && math.abs(sm.y - em.y) < 35) {
em.exploded = true; sm.active = false
interceptedCount += 1
for (i <- 0 until 25) blastParticles.append(new BlastParticle(em.x, em.y, 255, 255, 0))
}
}
}
}
}
// --- SCREENS ---
def drawIntroPart2(canvas: CanvasDraw) {
canvas.fill(10, 10, 15); canvas.rect(0, 0, cwidth, cheight)
canvas.fill(255, 60, 60); canvas.text("THIS IS A SECOND PART", cwidth / 2.0 - 120, cheight / 2.0 + 30)
canvas.fill(255, 215, 0); canvas.text("OPERATION SINDOOR: BORDER WARRIORS", cwidth / 2.0 - 160, cheight / 2.0 - 10)
canvas.fill(200, 200, 200); canvas.text("CLICK ANYWHERE TO READ MISSION BRIEFING", cwidth / 2.0 - 150, cheight / 2.0 - 60)
}
def drawLetterScreen(canvas: CanvasDraw) {
canvas.fill(245, 240, 220); canvas.stroke(100, 80, 50); canvas.strokeWeight(3)
val lx = cwidth / 2.0 - 270.0; val ly = cheight / 2.0 - 210.0
canvas.rect(lx, ly, 540, 430)
canvas.fill(180, 30, 30); canvas.noStroke(); canvas.rect(lx, ly + 380, 540, 50)
canvas.fill(255, 255, 255); canvas.text("TOP SECRET // DEFENCE HQ INDIA - PART 2", lx + 15, ly + 398)
canvas.fill(20, 20, 30)
canvas.text("COMMANDER RECALL & EMERGENCY ORDER", lx + 20, ly + 345)
canvas.text("Enemy forces have launched high-speed strategic missiles", lx + 20, ly + 310)
canvas.text("(PAKF-16, BABUR, SHAHEEN-3) across western borders!", lx + 20, ly + 285)
canvas.fill(180, 30, 30)
canvas.text("YOUR OBJECTIVE:", lx + 20, ly + 245)
canvas.fill(20, 20, 30)
canvas.text("1. Board the lead Heavy Main Battle Tank.", lx + 20, ly + 220)
canvas.text("2. Command 3 Auto Support Tanks & Air Defence Launcher.", lx + 20, ly + 195)
canvas.text("3. Intercept & Destroy at least 12 PAK missiles in 50s!", lx + 20, ly + 170)
if (letterTimer > 0) {
canvas.fill(150, 150, 150); canvas.rect(lx + 120, ly + 20, 300, 35)
canvas.fill(255, 255, 255); canvas.text("PLEASE READ THE LETTER...", lx + 165, ly + 32)
} else {
canvas.fill(20, 140, 40); canvas.rect(lx + 120, ly + 20, 300, 35)
canvas.fill(255, 255, 255); canvas.text("CLICK TO ACCEPT & DEPLOY", lx + 155, ly + 32)
}
}
def drawPlayerTank(canvas: CanvasDraw, tx: Double, ty: Double) {
canvas.fill(30, 33, 38); canvas.stroke(10, 10, 12); canvas.strokeWeight(1)
canvas.rect(tx - 45, ty, 90, 20)
canvas.fill(70, 75, 70)
for (i <- -3 to 3) canvas.ellipse(tx + (i * 12), ty + 10, 9, 9)
canvas.fill(80, 110, 65); canvas.rect(tx - 35, ty + 20, 70, 18)
canvas.fill(50, 85, 45); canvas.ellipse(tx, ty + 38, 40, 22)
val turretBaseX = tx; val turretBaseY = ty + 38.0
canvas.stroke(25, 50, 20); canvas.strokeWeight(8)
val tipX = turretBaseX + math.cos(playerCannonAngle) * 55.0
val tipY = turretBaseY + math.sin(playerCannonAngle) * 55.0
canvas.line(turretBaseX, turretBaseY, tipX, tipY)
if (muzzleFlashTimer > 0) {
canvas.noStroke(); canvas.fill(255, 140, 0, 230); canvas.ellipse(tipX, tipY, 30, 30)
}
}
def drawHUD(canvas: CanvasDraw) {
canvas.fill(255, 215, 0)
canvas.text(s"TIME: ${math.max(0, timer.toInt)}s", 20, cheight - 20)
canvas.text(s"PAK MISSILES DESTROYED: $interceptedCount / $targetKills", 140, cheight - 20)
canvas.text(s"DEFENCE: $baseHealth%", 420, cheight - 20)
canvas.fill(20, 20, 35, 200); canvas.rect(390, 85, 250, 50)
canvas.fill(if (selectedMissileType == 1) 200 else 80, 30, 30); canvas.rect(400, 95, 45, 30); canvas.fill(255, 255, 255); canvas.text("BRM", 408, 105)
canvas.fill(if (selectedMissileType == 2) 200 else 80, 30, 30); canvas.rect(450, 95, 45, 30); canvas.fill(255, 255, 255); canvas.text("AGN", 458, 105)
canvas.fill(if (selectedMissileType == 3) 200 else 80, 30, 30); canvas.rect(500, 95, 45, 30); canvas.fill(255, 255, 255); canvas.text("SUD", 508, 105)
canvas.fill(140, 0, 180); canvas.rect(555, 95, 75, 30); canvas.fill(255, 255, 255); canvas.text("LAUNCH", 568, 105)
}
def viewState(canvas: CanvasDraw) {
if (gameState == 0) { drawIntroPart2(canvas); return }
if (gameState == 1) { drawLetterScreen(canvas); return }
if (gameState == 2) {
canvas.fill(30, 30, 40); canvas.rect(0, 0, cwidth, cheight)
canvas.fill(50, 40, 30); canvas.rect(0, 0, cwidth, 35)
drawCutsceneTank(canvas, cutsceneTankX, 30)
if (!heroInside) drawArmyMan(canvas, heroX, 30)
canvas.fill(255, 255, 255); canvas.text("SOLDIER ENTERING TANK HATCH...", cwidth / 2.0 - 110, cheight - 50)
return
}
canvas.fill(10, 10, 25, 50); canvas.noStroke(); canvas.rect(0, 0, cwidth, cheight)
if (gameState == 3) {
repeatFor(blastParticles) { bp => bp.view(canvas) }
repeatFor(allyTanks) { at => at.view(canvas) }
drawPlayerTank(canvas, playerTankX, playerTankY)
repeatFor(tankShells) { s => s.view(canvas) }
repeatFor(strategicMissiles) { sm => sm.view(canvas) }
repeatFor(enemyMissiles) { em => em.view(canvas) }
drawHUD(canvas)
} else if (gameState == 4) {
repeatFor(fireworks) { f => f.view(canvas) }
canvas.fill(0, 0, 0, 180); canvas.rect(0, 0, cwidth, cheight)
canvas.fill(255, 153, 51); canvas.text("VICTORY! PAKISTAN MISSILE THREAT DESTROYED!", cwidth / 2.0 - 180, cheight / 2.0 + 30)
canvas.fill(18, 136, 7); canvas.text("INDIA IS SAFE! JAI HIND!", cwidth / 2.0 - 90, cheight / 2.0 - 20)
} else if (gameState == 5) {
canvas.fill(0, 0, 0, 200); canvas.rect(0, 0, cwidth, cheight)
canvas.fill(255, 50, 50); canvas.text("MISSION FAILED! BORDER BREACHED!", cwidth / 2.0 - 130, cheight / 2.0)
}
}
animateWithCanvasDraw { canvas =>
updateState()
viewState(canvas)
}