Code Sketch
sniper
Category: Art
import scala.util.Random //> import scala.util.Random
// Clear canvas and set normal speed
clear()
invisible()
setSpeed(medium)
// --- Game Settings ---
val maxBalls = 12 // 2 Overs = 12 Balls //> val maxBalls: Int = 12
val maxWickets = 10 //> val maxWickets: Int = 10
// --- Match State Variables ---
var currentInning = 1 // 1 = AI Batting, 2 = Player Batting //> var currentInning: Int = 1
var ballsBowled = 0 //> var ballsBowled: Int = 0
var runs = 0 //> var runs: Int = 0
var wickets = 0 //> var wickets: Int = 0
var targetRuns = 0 //> var targetRuns: Int = 0
var aiRuns = 0 //> var aiRuns: Int = 0
var aiWickets = 0 //> var aiWickets: Int = 0
var ballX = -200.0 //> var ballX: Double = -200.0
var ballY = 0.0 //> var ballY: Double = 0.0
var ballVx = 0.0 //> var ballVx: Double = 0.0
var ballVy = 0.0 //> var ballVy: Double = 0.0
var swingFactor = 0.0 //> var swingFactor: Double = 0.0
var isBowled = false //> var isBowled: Boolean = false
var isHit = false //> var isHit: Boolean = false
// --- Bowler Run-Up Variables ---
var bowlerX = -260.0 //> var bowlerX: Double = -260.0
var bowlerY = 0.0 //> var bowlerY: Double = 0.0
var isRunningUp = false //> var isRunningUp: Boolean = false
var strideState = 0 //> var strideState: Int = 0
var bowlingPhase = "RUNUP" //> var bowlingPhase: String = RUNUP
// --- Original Bat Animation Variables ---
var batAngle = 0.0 //> var batAngle: Double = 0.0
var isSwinging = false //> var isSwinging: Boolean = false
var swingTimer = 0 //> var swingTimer: Int = 0
// --- Stump Light Variables ---
var stumpLightTimer = 0 //> var stumpLightTimer: Int = 0
var isStumpGlowing = false //> var isStumpGlowing: Boolean = false
// Milestone & Celebration
var nextMilestone = 50 //> var nextMilestone: Int = 50
var showCelebration = false //> var showCelebration: Boolean = false
var celebrationTimer = 0 //> var celebrationTimer: Int = 0
var statusMessage = "INNING 1: Press SPACE to Bowl to AI!" //> var statusMessage: String = INNING 1: Press SPACE to Bowl to AI!
// ==========================================
// ?? HIGH-DETAIL REALISTIC STADIUM & PITCH
// ==========================================
val ground = Picture.rectangle(600, 400) //> val ground: net.kogics.kojo.picture.RectanglePic = Picture with Id: 960227835
ground.setFillColor(Color(34, 139, 34))
ground.setPenColor(noColor)
ground.setPosition(-300, -200)
ground.draw()
// Outfield Turf Grass Pattern Lines
for (i <- -300 to 300 by 40) {
val grassStrip = Picture.rectangle(20, 400)
grassStrip.setFillColor(Color(46, 160, 46))
grassStrip.setPenColor(noColor)
grassStrip.setPosition(i, -200)
grassStrip.draw()
}
// ? Realistic Turf Pitch Base
val pitchBase = Picture.rectangle(420, 84) //> val pitchBase: net.kogics.kojo.picture.RectanglePic = Picture with Id: 1006851865
pitchBase.setFillColor(Color(160, 120, 80))
pitchBase.setPenColor(noColor)
pitchBase.setPosition(-210, -42)
pitchBase.draw()
val pitch = Picture.rectangle(400, 76) //> val pitch: net.kogics.kojo.picture.RectanglePic = Picture with Id: 46027553
pitch.setFillColor(Color(218, 190, 145))
pitch.setPenColor(noColor)
pitch.setPosition(-200, -38)
pitch.draw()
// Realistic Pitch Center Wear Patch
val wearPatch = Picture.rectangle(120, 50) //> val wearPatch: net.kogics.kojo.picture.RectanglePic = Picture with Id: 257681888
wearPatch.setFillColor(Color(205, 175, 130))
wearPatch.setPenColor(noColor)
wearPatch.setPosition(-60, -25)
wearPatch.draw()
// White Crease Lines Setup
def createCreaseLine(w: Int, h: Int, x: Int, y: Int): Picture = {
val line = Picture.rectangle(w, h)
line.setFillColor(cm.white)
line.setPenColor(noColor)
line.setPosition(x, y)
line.draw()
line
} //> def createCreaseLine(w: Int, h: Int, x: Int, y: Int): builtins.Picture
// Bowler End Creases (-180 X)
createCreaseLine(3, 76, -180, -38) //> val res20: builtins.Picture = Picture with Id: 6918805
createCreaseLine(35, 2, -200, 30) //> val res21: builtins.Picture = Picture with Id: 1935857791
createCreaseLine(35, 2, -200, -32) //> val res22: builtins.Picture = Picture with Id: 1809519564
// Batsman End Creases (180 X)
createCreaseLine(3, 76, 180, -38) //> val res23: builtins.Picture = Picture with Id: 1305994813
createCreaseLine(35, 2, 165, 30) //> val res24: builtins.Picture = Picture with Id: 428037294
createCreaseLine(35, 2, 165, -32) //> val res25: builtins.Picture = Picture with Id: 28123391
// ==========================================
// ? BOWLER DESIGN
// ==========================================
val bowlerShadow = Picture.ellipse(28, 10) //> val bowlerShadow: net.kogics.kojo.picture.EllipsePic = Picture with Id: 1314824624
bowlerShadow.setFillColor(Color(20, 80, 20))
bowlerShadow.setPenColor(noColor)
bowlerShadow.draw()
val shoeL = Picture.rectangle(6, 4); shoeL.setFillColor(cm.white); shoeL.draw() //> val shoeL: net.kogics.kojo.picture.RectanglePic = Picture with Id: 523767388
val shoeR = Picture.rectangle(6, 4); shoeR.setFillColor(cm.white); shoeR.draw() //> val shoeR: net.kogics.kojo.picture.RectanglePic = Picture with Id: 2098328676
val legL = Picture.rectangle(5, 16); legL.setFillColor(Color(220, 220, 220)); legL.draw() //> val legL: net.kogics.kojo.picture.RectanglePic = Picture with Id: 1555785846
val legR = Picture.rectangle(5, 16); legR.setFillColor(Color(220, 220, 220)); legR.draw() //> val legR: net.kogics.kojo.picture.RectanglePic = Picture with Id: 2145122684
val torsoBase = Picture.rectangle(16, 22); torsoBase.setFillColor(Color(0, 102, 204)); torsoBase.draw() //> val torsoBase: net.kogics.kojo.picture.RectanglePic = Picture with Id: 36885694
val torsoHighlight = Picture.rectangle(8, 22); torsoHighlight.setFillColor(Color(51, 153, 255)); torsoHighlight.setPenColor(noColor); torsoHighlight.draw() //> val torsoHighlight: net.kogics.kojo.picture.RectanglePic = Picture with Id: 160697123
val armL = Picture.rectangle(4, 18); armL.setFillColor(Color(220, 220, 220)); armL.draw() //> val armL: net.kogics.kojo.picture.RectanglePic = Picture with Id: 2028566246
val armR = Picture.rectangle(4, 20); armR.setFillColor(Color(220, 220, 220)); armR.draw() //> val armR: net.kogics.kojo.picture.RectanglePic = Picture with Id: 919379785
val head = Picture.circle(7); head.setFillColor(Color(240, 190, 150)); head.draw() //> val head: net.kogics.kojo.picture.CirclePic = Picture with Id: 868827855
val cap = Picture.circle(7); cap.setFillColor(Color(0, 51, 153)); cap.draw() //> val cap: net.kogics.kojo.picture.CirclePic = Picture with Id: 583669009
def updateBowlerPosition(x: Double, y: Double, phase: String): Unit = {
bowlerShadow.setPosition(x - 14, -22)
shoeL.setPosition(x - 6, -18 + y)
shoeR.setPosition(x + 4, -18 + y)
legL.setPosition(x - 5, -14 + y)
legR.setPosition(x + 5, -14 + y)
torsoBase.setPosition(x - 8, 0 + y)
torsoHighlight.setPosition(x - 8, 0 + y)
phase match {
case "JUMP" =>
armL.setHeading(90); armR.setHeading(-120); legL.setHeading(20); legR.setHeading(-20)
case "RELEASE" =>
armL.setHeading(-45); armR.setHeading(110); legL.setHeading(-10); legR.setHeading(30)
case "FOLLOW_THROUGH" =>
armL.setHeading(-60); armR.setHeading(20); legL.setHeading(0); legR.setHeading(0)
case _ =>
if (strideState % 2 == 0) {
armL.setHeading(55); armR.setHeading(-55); legL.setHeading(15); legR.setHeading(-15)
} else {
armL.setHeading(-40); armR.setHeading(70); legL.setHeading(-15); legR.setHeading(-15)
}
}
armL.setPosition(x - 12, 10 + y)
armR.setPosition(x + 4, 12 + y)
head.setPosition(x, 20 + y)
cap.setPosition(x, 24 + y)
} //> def updateBowlerPosition(x: Double, y: Double, phase: String): Unit
updateBowlerPosition(bowlerX, bowlerY, "RUNUP")
// ==========================================
// ? BATSMAN & ICONIC MRF CRICKET BAT DESIGN
// ==========================================
val batsman = Picture.circle(12) //> val batsman: net.kogics.kojo.picture.CirclePic = Picture with Id: 2001958992
batsman.setFillColor(cm.blue)
batsman.setPosition(180, 0)
batsman.draw()
// --- Premium MRF Genius Bat ---
val batBlade = Picture.rectangle(11, 32) //> val batBlade: net.kogics.kojo.picture.RectanglePic = Picture with Id: 1423477804
batBlade.setFillColor(Color(222, 184, 135)) // English Willow
batBlade.setPenColor(Color(139, 69, 19))
val batSpine = Picture.rectangle(3, 32) //> val batSpine: net.kogics.kojo.picture.RectanglePic = Picture with Id: 1726255939
batSpine.setFillColor(Color(205, 133, 63))
batSpine.setPenColor(noColor)
// ? MRF Signature Red Base Sticker
val mrfStickerBase = Picture.rectangle(9, 12) //> val mrfStickerBase: net.kogics.kojo.picture.RectanglePic = Picture with Id: 1875319231
mrfStickerBase.setFillColor(Color(220, 0, 0)) // MRF Bright Red
mrfStickerBase.setPenColor(noColor)
// ? MRF White Block Logo Layer
val mrfTextWhite = Picture.rectangle(7, 4) //> val mrfTextWhite: net.kogics.kojo.picture.RectanglePic = Picture with Id: 982666668
mrfTextWhite.setFillColor(cm.white)
mrfTextWhite.setPenColor(noColor)
val batShoulder = Picture.rectangle(7, 4) //> val batShoulder: net.kogics.kojo.picture.RectanglePic = Picture with Id: 591912629
batShoulder.setFillColor(Color(210, 170, 120))
batShoulder.setPenColor(Color(139, 69, 19))
// ? MRF Red/Black Rubber Grip Handle
val batHandle = Picture.rectangle(4, 14) //> val batHandle: net.kogics.kojo.picture.RectanglePic = Picture with Id: 1386834686
batHandle.setFillColor(Color(220, 0, 0)) // Red Rubber Top Grip
batHandle.setPenColor(Color(100, 0, 0))
val batGripBottom = Picture.rectangle(4, 7) //> val batGripBottom: net.kogics.kojo.picture.RectanglePic = Picture with Id: 1156672733
batGripBottom.setFillColor(Color(20, 20, 20)) // Black Rubber Lower Grip
batGripBottom.setPenColor(noColor)
def updateBatPosition(headingAngle: Double): Unit = {
batBlade.setHeading(headingAngle)
batSpine.setHeading(headingAngle)
mrfStickerBase.setHeading(headingAngle)
mrfTextWhite.setHeading(headingAngle)
batShoulder.setHeading(headingAngle)
batHandle.setHeading(headingAngle)
batGripBottom.setHeading(headingAngle)
if (headingAngle == 0.0) {
batBlade.setPosition(173, -28)
batSpine.setPosition(173, -28)
mrfStickerBase.setPosition(174, -14)
mrfTextWhite.setPosition(175, -10)
batShoulder.setPosition(175, 2)
batHandle.setPosition(176, 5)
batGripBottom.setPosition(176, 5)
} else {
batBlade.setPosition(162, -20)
batSpine.setPosition(162, -20)
mrfStickerBase.setPosition(170, -10)
mrfTextWhite.setPosition(171, -6)
batShoulder.setPosition(176, 2)
batHandle.setPosition(178, 5)
batGripBottom.setPosition(178, 5)
}
} //> def updateBatPosition(headingAngle: Double): Unit
batBlade.draw()
batSpine.draw()
mrfStickerBase.draw()
mrfTextWhite.draw()
batShoulder.draw()
batHandle.draw()
batGripBottom.draw()
updateBatPosition(0.0)
// ==========================================
// ? REALISTIC 3D WICKETS
// ==========================================
val stumpShadow = Picture.ellipse(22, 6) //> val stumpShadow: net.kogics.kojo.picture.EllipsePic = Picture with Id: 1996951413
stumpShadow.setFillColor(Color(160, 130, 90))
stumpShadow.setPenColor(noColor)
stumpShadow.setPosition(215, -22)
stumpShadow.draw()
val stumpBase = Picture.rectangle(18, 4) //> val stumpBase: net.kogics.kojo.picture.RectanglePic = Picture with Id: 1532876669
stumpBase.setFillColor(Color(100, 100, 100))
stumpBase.setPenColor(noColor)
stumpBase.setPosition(217, -20)
stumpBase.draw()
val stump1 = Picture.rectangle(3, 30) //> val stump1: net.kogics.kojo.picture.RectanglePic = Picture with Id: 797890432
val stump2 = Picture.rectangle(3, 30) //> val stump2: net.kogics.kojo.picture.RectanglePic = Picture with Id: 2015030199
val stump3 = Picture.rectangle(3, 30) //> val stump3: net.kogics.kojo.picture.RectanglePic = Picture with Id: 306851795
val defaultStumpColor = Color(245, 222, 179) //> val defaultStumpColor: java.awt.Color = java.awt.Color[r=245,g=222,b=179]
val defaultStumpBorder = Color(139, 69, 19) //> val defaultStumpBorder: java.awt.Color = java.awt.Color[r=139,g=69,b=19]
stump1.setFillColor(defaultStumpColor); stump1.setPenColor(defaultStumpBorder); stump1.setPosition(217, -18); stump1.draw()
stump2.setFillColor(defaultStumpColor); stump2.setPenColor(defaultStumpBorder); stump2.setPosition(224, -18); stump2.draw()
stump3.setFillColor(defaultStumpColor); stump3.setPenColor(defaultStumpBorder); stump3.setPosition(231, -18); stump3.draw()
val bail1 = Picture.rectangle(7, 3) //> val bail1: net.kogics.kojo.picture.RectanglePic = Picture with Id: 1820347806
val bail2 = Picture.rectangle(7, 3) //> val bail2: net.kogics.kojo.picture.RectanglePic = Picture with Id: 3324030
bail1.setFillColor(defaultStumpColor); bail1.setPenColor(defaultStumpBorder); bail1.setPosition(217, 12); bail1.draw()
bail2.setFillColor(defaultStumpColor); bail2.setPenColor(defaultStumpBorder); bail2.setPosition(224, 12); bail2.draw()
val stumpGlow = Picture.ellipse(32, 45) //> val stumpGlow: net.kogics.kojo.picture.EllipsePic = Picture with Id: 43426301
stumpGlow.setFillColor(Color(0, 191, 255))
stumpGlow.setPenColor(noColor)
stumpGlow.setPosition(210, -20)
stumpGlow.draw()
stumpGlow.setOpacity(0.0)
def triggerStumpBlueLight(): Unit = {
isStumpGlowing = true
stumpLightTimer = 25
stumpGlow.setOpacity(0.85)
val glowColor = Color(0, 238, 255)
val glowBorder = Color(255, 255, 255)
stump1.setFillColor(glowColor); stump1.setPenColor(glowBorder)
stump2.setFillColor(glowColor); stump2.setPenColor(glowBorder)
stump3.setFillColor(glowColor); stump3.setPenColor(glowBorder)
bail1.setFillColor(glowColor); bail1.setPenColor(glowBorder)
bail2.setFillColor(glowColor); bail2.setPenColor(glowBorder)
} //> def triggerStumpBlueLight(): Unit
def turnOffStumpLight(): Unit = {
isStumpGlowing = false
stumpGlow.setOpacity(0.0)
stump1.setFillColor(defaultStumpColor); stump1.setPenColor(defaultStumpBorder)
stump2.setFillColor(defaultStumpColor); stump2.setPenColor(defaultStumpBorder)
stump3.setFillColor(defaultStumpColor); stump3.setPenColor(defaultStumpBorder)
bail1.setFillColor(defaultStumpColor); bail1.setPenColor(defaultStumpBorder)
bail2.setFillColor(defaultStumpColor); bail2.setPenColor(defaultStumpBorder)
} //> def turnOffStumpLight(): Unit
// ==========================================
// ? WHITE BALL
// ==========================================
val ballShadow = Picture.ellipse(12, 4) //> val ballShadow: net.kogics.kojo.picture.EllipsePic = Picture with Id: 2050065276
ballShadow.setFillColor(Color(150, 130, 100))
ballShadow.setPenColor(noColor)
ballShadow.draw()
val ball = Picture.circle(6) //> val ball: net.kogics.kojo.picture.CirclePic = Picture with Id: 13617876
ball.setFillColor(Color(255, 255, 255))
ball.setPenColor(Color(180, 180, 180))
ball.draw()
def updateBallPosition(x: Double, y: Double): Unit = {
ball.setPosition(x, y)
ballShadow.setPosition(x - 6, y - 12)
} //> def updateBallPosition(x: Double, y: Double): Unit
updateBallPosition(ballX, ballY)
// Confetti Particles
val confetti1 = Picture.circle(8); confetti1.setPosition(0, 50); confetti1.draw(); confetti1.setOpacity(0.0) //> val confetti1: net.kogics.kojo.picture.CirclePic = Picture with Id: 2012426740
val confetti2 = Picture.circle(10); confetti2.setPosition(-80, 80); confetti2.draw(); confetti2.setOpacity(0.0) //> val confetti2: net.kogics.kojo.picture.CirclePic = Picture with Id: 1007311555
val confetti3 = Picture.circle(7); confetti3.setPosition(80, 70); confetti3.draw(); confetti3.setOpacity(0.0) //> val confetti3: net.kogics.kojo.picture.CirclePic = Picture with Id: 463370086
val confetti4 = Picture.circle(9); confetti4.setPosition(-120, 20); confetti4.draw(); confetti4.setOpacity(0.0) //> val confetti4: net.kogics.kojo.picture.CirclePic = Picture with Id: 1777410127
// ==========================================
// ? SCOREBOARD UI
// ==========================================
val boxPlayer = Picture.rectangle(260, 50); boxPlayer.setFillColor(Color(20, 20, 20)); boxPlayer.setPenColor(Color(0, 230, 118)); boxPlayer.setPenThickness(2); boxPlayer.setPosition(-285, 120); boxPlayer.draw() //> val boxPlayer: net.kogics.kojo.picture.RectanglePic = Picture with Id: 888855302
val textPlayer = Picture.text("", 11); textPlayer.setFillColor(cm.white); textPlayer.setPosition(-275, 160); textPlayer.draw() //> val textPlayer: net.kogics.kojo.picture.TextPic = TextPic (Id: 247840019)
val boxAI = Picture.rectangle(260, 50); boxAI.setFillColor(Color(20, 20, 20)); boxAI.setPenColor(Color(255, 82, 82)); boxAI.setPenThickness(2); boxAI.setPosition(25, 120); boxAI.draw() //> val boxAI: net.kogics.kojo.picture.RectanglePic = Picture with Id: 1931646632
val textAI = Picture.text("", 11); textAI.setFillColor(cm.white); textAI.setPosition(35, 160); textAI.draw() //> val textAI: net.kogics.kojo.picture.TextPic = TextPic (Id: 1533356422)
val statusText = Picture.text("", 11); statusText.setFillColor(cm.yellow); statusText.setPosition(-280, -180); statusText.draw() //> val statusText: net.kogics.kojo.picture.TextPic = TextPic (Id: 1169822383)
def getOversString(balls: Int): String = s"${balls / 6}.${balls % 6} Ov" //> def getOversString(balls: Int): String
def updateScoreDisplay(): Unit = {
if (currentInning == 1) {
textAI.update(s"TEAM AI (Batting)\nRuns: $aiRuns | Wkts: $aiWickets/$maxWickets | ${getOversString(ballsBowled)}/2.0")
textPlayer.update(s"TEAM SNIPER\nYet to Bat (Target: TBD)")
} else {
textAI.update(s"TEAM AI (Batting Done)\nScore: $aiRuns/$aiWickets in 2.0 Ov")
textPlayer.update(s"TEAM SNIPER (Chasing)\nRuns: $runs/$wickets | Target: $targetRuns | ${getOversString(ballsBowled)}/2.0")
}
statusText.update(statusMessage)
} //> def updateScoreDisplay(): Unit
updateScoreDisplay()
def triggerCelebration(): Unit = {
showCelebration = true; celebrationTimer = 40
confetti1.setOpacity(1.0); confetti2.setOpacity(1.0); confetti3.setOpacity(1.0); confetti4.setOpacity(1.0)
} //> def triggerCelebration(): Unit
def hideCelebration(): Unit = {
showCelebration = false
confetti1.setOpacity(0.0); confetti2.setOpacity(0.0); confetti3.setOpacity(0.0); confetti4.setOpacity(0.0)
} //> def hideCelebration(): Unit
def switchInnings(): Unit = {
currentInning = 2; targetRuns = aiRuns + 1; ballsBowled = 0
isBowled = false; isHit = false; isRunningUp = false
bowlerX = -260.0; bowlerY = 0.0; bowlingPhase = "RUNUP"
updateBowlerPosition(bowlerX, bowlerY, bowlingPhase)
statusMessage = s"INNING 2: You Need $targetRuns Runs to Win! Press SPACE to Bowl & Bat."
updateScoreDisplay()
} //> def switchInnings(): Unit
def checkMatchEnd(): Unit = {
if (runs >= targetRuns) {
statusMessage = s"? CONGRATS! TEAM SNIPER WON BY ${maxWickets - wickets} WICKETS! ?"
triggerCelebration()
} else if (ballsBowled >= maxBalls || wickets >= maxWickets) {
if (runs < targetRuns - 1) {
statusMessage = s"MATCH OVER! TEAM AI WON BY ${targetRuns - 1 - runs} RUNS! Press 'R' to Restart."
} else {
statusMessage = "MATCH TIED! Equal Scores."
}
}
} //> def checkMatchEnd(): Unit
def startRunUp(): Unit = {
if (currentInning == 1 && (ballsBowled >= maxBalls || aiWickets >= maxWickets)) { switchInnings(); return }
if (currentInning == 2 && (ballsBowled >= maxBalls || wickets >= maxWickets || runs >= targetRuns)) { checkMatchEnd(); updateScoreDisplay(); return }
if (!isBowled && !isRunningUp) {
isRunningUp = true; bowlerX = -260.0; bowlerY = 0.0; bowlingPhase = "RUNUP"
statusMessage = "Bowler running in with Controlled Swing..."
updateScoreDisplay()
}
} //> def startRunUp(): Unit
// --- Dynamic Ball Release ---
def releaseBall(): Unit = {
isBowled = true; isHit = false; ballsBowled += 1; ballX = -190.0; ballY = 0.0
ballVx = 6.0 + (Random.nextDouble() * 2.0)
swingFactor = if (Random.nextBoolean()) 0.02 else -0.02
ballVy = -swingFactor * 15
val swingType = if (swingFactor > 0) "IN-SWING ?" else "OUT-SWING ?"
statusMessage = if (currentInning == 1) s"Ball Delivered ($swingType)! AI Playing..." else s"$swingType! 'S': Straight | 'D': Cover | 'W': Pull"
updateScoreDisplay()
} //> def releaseBall(): Unit
// --- Player Batting (Inning 2) ---
def swingBat(shotType: String): Unit = {
if (currentInning != 2 || wickets >= maxWickets) return
if (!isSwinging) {
isSwinging = true
swingTimer = 10
updateBatPosition(-45.0)
}
if (isBowled && !isHit) {
if (ballX >= 90 && ballX <= 190) {
isHit = true
val timing = math.abs(ballX - 150)
shotType match {
case "STRAIGHT" =>
if (timing < 25) { runs += 6; statusMessage = "SIXER! Straight Shot!"; ballVx = -(8.0 + Random.nextDouble() * 2.0); ballVy = 0.0 }
else { runs += 4; statusMessage = "FOUR! Straight Drive!"; ballVx = -(6.0 + Random.nextDouble() * 2.0); ballVy = 0.5 }
case "COVER" =>
if (timing < 25) { runs += 6; statusMessage = "SIXER! Cover Drive!"; ballVx = -(7.0 + Random.nextDouble() * 2.0); ballVy = -(4.0 + Random.nextDouble() * 2.0) }
else { runs += 4; statusMessage = "FOUR! Cover Shot!"; ballVx = -(5.0 + Random.nextDouble() * 2.0); ballVy = -(3.0 + Random.nextDouble() * 2.0) }
case _ =>
if (timing < 25) { runs += 6; statusMessage = "SIXER! Pull Shot!"; ballVx = -(7.5 + Random.nextDouble() * 2.0); ballVy = 4.0 + Random.nextDouble() * 2.0 }
else { runs += 4; statusMessage = "FOUR! Pull Shot!"; ballVx = -(5.5 + Random.nextDouble() * 2.0); ballVy = -2.0 - Random.nextDouble() * 2.0 }
}
checkMatchEnd()
} else {
statusMessage = "MISSED THE BALL!"
}
updateScoreDisplay()
}
} //> def swingBat(shotType: String): Unit
// --- AI Batting (Inning 1) ---
def aiAutoPlay(): Unit = {
if (currentInning == 1 && isBowled && !isHit && ballX >= 110 && ballX <= 180) {
val chance = Random.nextInt(100)
if (chance < 50) {
isSwinging = true
swingTimer = 10
updateBatPosition(-45.0)
isHit = true
val shotType = Random.nextInt(100)
if (shotType < 20) { aiRuns += 6; statusMessage = "TEAM AI Hit a SIX!"; ballVx = -(8.0 + Random.nextDouble() * 2.0); ballVy = 3.0 + Random.nextDouble() * 2.0 }
else if (shotType < 60) { aiRuns += 4; statusMessage = "TEAM AI Hit a FOUR!"; ballVx = -(6.0 + Random.nextDouble() * 2.0); ballVy = -2.0 - Random.nextDouble() * 2.0 }
else { aiRuns += 1 + Random.nextInt(2); statusMessage = "TEAM AI Took Runs!"; ballVx = -(4.0 + Random.nextDouble() * 1.0); ballVy = -1.0 }
} else {
if (Random.nextInt(100) < 30) ballVy = -0.5 else statusMessage = "TEAM AI Beaten By Swing!"
}
updateScoreDisplay()
}
} //> def aiAutoPlay(): Unit
def resetGame(): Unit = {
currentInning = 1; ballsBowled = 0; runs = 0; wickets = 0; targetRuns = 0; aiRuns = 0; aiWickets = 0
nextMilestone = 50; isBowled = false; isHit = false; isRunningUp = false
bowlerX = -260.0; bowlerY = 0.0; bowlingPhase = "RUNUP"
isSwinging = false; updateBatPosition(0.0)
updateBowlerPosition(bowlerX, bowlerY, bowlingPhase)
turnOffStumpLight(); hideCelebration()
statusMessage = "Game Reset! INNING 1: Press SPACE to Bowl to AI."
updateScoreDisplay()
} //> def resetGame(): Unit
// --- Key Listeners ---
onKeyPress { key =>
key match {
case ' ' => startRunUp()
case 's' | 'S' => if (currentInning == 2) swingBat("STRAIGHT")
case 'd' | 'D' => if (currentInning == 2) swingBat("COVER")
case 'w' | 'W' => if (currentInning == 2) swingBat("PULL")
case 'r' | 'R' => resetGame()
case _ =>
}
}
// --- Main Game Loop ---
animate {
if (showCelebration) {
celebrationTimer -= 1
confetti1.setFillColor(Color(Random.nextInt(255), Random.nextInt(255), Random.nextInt(255)))
confetti2.setFillColor(Color(Random.nextInt(255), Random.nextInt(255), Random.nextInt(255)))
confetti3.setFillColor(Color(Random.nextInt(255), Random.nextInt(255), Random.nextInt(255)))
confetti4.setFillColor(Color(Random.nextInt(255), Random.nextInt(255), Random.nextInt(255)))
if (celebrationTimer <= 0) hideCelebration()
}
if (isStumpGlowing) {
stumpLightTimer -= 1
if (stumpLightTimer <= 0) turnOffStumpLight()
}
// Bowler Run-Up
if (isRunningUp) {
if (bowlerX < -220.0) { bowlerX += 6.0; strideState += 1; bowlingPhase = "RUNUP" }
else if (bowlerX < -205.0) { bowlerX += 5.0; bowlerY = 10.0; bowlingPhase = "JUMP" }
else if (bowlerX < -195.0) { bowlerX += 4.0; bowlerY = 3.0; bowlingPhase = "RELEASE" }
else { isRunningUp = false; bowlerY = 0.0; bowlingPhase = "FOLLOW_THROUGH"; releaseBall() }
updateBowlerPosition(bowlerX, bowlerY, bowlingPhase)
}
// Bat Reset Animation
if (isSwinging) {
swingTimer -= 1
if (swingTimer <= 0) {
isSwinging = false
updateBatPosition(0.0)
}
}
// Controlled Ball Movement
if (isBowled) {
ballX += ballVx
if (!isHit) {
ballVy += swingFactor
if (ballY > 25.0) ballY = 25.0
if (ballY < -25.0) ballY = -25.0
}
ballY += ballVy
updateBallPosition(ballX, ballY)
if (currentInning == 1) aiAutoPlay()
// Bowled Check
if (!isHit && ballX > 213) {
isBowled = false
triggerStumpBlueLight()
if (currentInning == 1) {
aiWickets += 1
statusMessage = s"OUT! YOU TOOK AI'S WICKET! ? ($aiWickets/$maxWickets Wkts)"
if (aiWickets >= maxWickets || ballsBowled >= maxBalls) switchInnings()
} else {
wickets += 1
statusMessage = s"BOWLED OUT! ? LED LIGHTS GLOWING! ($wickets/$maxWickets Wkts)"
checkMatchEnd()
}
updateScoreDisplay()
}
if (ballX < -340 || ballX > 340 || ballY < -200 || ballY > 200) {
isBowled = false
if (currentInning == 1 && ballsBowled >= maxBalls) switchInnings()
else if (currentInning == 2) checkMatchEnd()
}
}
} //> val res101: java.util.concurrent.Future[edu.umd.cs.piccolo.activities.PActivity] = net.kogics.kojo.util.FutureResult@283c3922