Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Whack-a-Mole for CC: Tweaked
- -- For a 4x3 monitor grid
- -- Find the monitor
- local monitor = peripheral.find("monitor")
- if not monitor then
- print("No monitor found! Please attach a monitor.")
- return
- end
- -- Set up the display
- monitor.setTextScale(0.5)
- local width, height = monitor.getSize()
- print("Monitor size: " .. width .. "x" .. height)
- -- Game constants
- local GRID_WIDTH = 4 -- 4 mole holes across
- local GRID_HEIGHT = 3 -- 3 mole holes down
- local MAX_ACTIVE_MOLES = 3
- local GAME_DURATION = 30 -- seconds
- -- Calculate cell dimensions
- local cellWidth = math.floor(width / GRID_WIDTH)
- local cellHeight = math.floor(height / GRID_HEIGHT)
- -- Create the grid of mole holes
- local grid = {}
- for x = 1, GRID_WIDTH do
- grid[x] = {}
- for y = 1, GRID_HEIGHT do
- grid[x][y] = {
- x = (x-1) * cellWidth + 1,
- y = (y-1) * cellHeight + 1,
- width = cellWidth,
- height = cellHeight,
- active = false,
- timeActive = 0
- }
- end
- end
- -- Helper function to draw a button
- local function drawButton(x, y, w, h, text, bgColor, textColor)
- monitor.setBackgroundColor(bgColor)
- for i = 0, h - 1 do
- monitor.setCursorPos(x, y + i)
- monitor.write(string.rep(" ", w))
- end
- monitor.setTextColor(textColor)
- local textX = x + math.floor((w - #text) / 2)
- local textY = y + math.floor(h / 2)
- monitor.setCursorPos(textX, textY)
- monitor.write(text)
- end
- -- Helper function to check if a point is inside a rectangle
- local function isInside(px, py, x, y, w, h)
- return px >= x and px < x + w and py >= y and py < y + h
- end
- -- Draw welcome screen
- local function drawWelcomeScreen()
- monitor.setBackgroundColor(colors.black)
- monitor.clear()
- -- Title
- monitor.setCursorPos(math.floor(width/2) - 6, math.floor(height/3))
- monitor.setTextColor(colors.yellow)
- monitor.write("WHACK-A-MOLE")
- -- Instructions
- monitor.setCursorPos(math.floor(width/2) - 10, math.floor(height/3) + 2)
- monitor.setTextColor(colors.white)
- monitor.write("Tap the moles as they appear!")
- -- Start button
- local buttonWidth = 12
- local buttonHeight = 3
- local buttonX = math.floor(width/2) - math.floor(buttonWidth/2)
- local buttonY = math.floor(height/3) + 5
- drawButton(buttonX, buttonY, buttonWidth, buttonHeight, "Start Game", colors.green, colors.white)
- return {
- startButton = {x = buttonX, y = buttonY, width = buttonWidth, height = buttonHeight}
- }
- end
- -- Main game function
- local function playGame(continuePrevious, prevScore, prevDifficulty)
- -- Game state - reset based on whether continuing or new game
- local gameState = {
- score = continuePrevious and prevScore or 0,
- timeLeft = GAME_DURATION,
- activeMoles = {},
- difficulty = continuePrevious and prevDifficulty or 1,
- isGameOver = false,
- startTime = os.epoch("local") / 1000,
- lastSpawnTime = os.epoch("local") / 1000
- }
- -- Clear all moles
- for x = 1, GRID_WIDTH do
- for y = 1, GRID_HEIGHT do
- grid[x][y].active = false
- grid[x][y].timeActive = 0
- end
- end
- print("GAME STARTED - Difficulty: " .. gameState.difficulty ..
- (continuePrevious and " (Continued)" or " (New Game)"))
- -- Draw the game board
- local function drawGame()
- monitor.setBackgroundColor(colors.green) -- Grass background
- monitor.clear()
- -- Draw each mole hole
- for x = 1, GRID_WIDTH do
- for y = 1, GRID_HEIGHT do
- local cell = grid[x][y]
- -- Draw the mole hole (brown circle)
- local holeColor = colors.brown
- local centerX = cell.x + math.floor(cell.width/2)
- local centerY = cell.y + math.floor(cell.height/2)
- -- Draw a circular hole
- for cy = -math.floor(cell.height/3), math.floor(cell.height/3) do
- for cx = -math.floor(cell.width/3), math.floor(cell.width/3) do
- if cx*cx + cy*cy <= (cell.width/3)*(cell.height/3) then
- monitor.setCursorPos(centerX + cx, centerY + cy)
- monitor.setBackgroundColor(holeColor)
- monitor.write(" ")
- end
- end
- end
- -- Draw mole if active
- if cell.active then
- -- Draw mole face (black with white eyes)
- for cy = -math.floor(cell.height/4), math.floor(cell.height/4) do
- for cx = -math.floor(cell.width/4), math.floor(cell.width/4) do
- if cx*cx + cy*cy <= (cell.width/4)*(cell.height/4) then
- monitor.setCursorPos(centerX + cx, centerY + cy)
- monitor.setBackgroundColor(colors.black)
- monitor.write(" ")
- end
- end
- end
- -- Draw eyes
- monitor.setCursorPos(centerX - 2, centerY - 1)
- monitor.setBackgroundColor(colors.white)
- monitor.write(" ")
- monitor.setCursorPos(centerX + 2, centerY - 1)
- monitor.setBackgroundColor(colors.white)
- monitor.write(" ")
- end
- end
- end
- -- Draw score and time
- monitor.setCursorPos(2, 2)
- monitor.setBackgroundColor(colors.black)
- monitor.setTextColor(colors.white)
- monitor.write("Score: " .. gameState.score)
- monitor.setCursorPos(width - 15, 2)
- monitor.setTextColor(colors.white)
- monitor.write("Time: " .. gameState.timeLeft .. "s")
- -- Debug info
- monitor.setCursorPos(2, height - 1)
- monitor.setTextColor(colors.white)
- monitor.write("Difficulty: " .. gameState.difficulty)
- end
- -- Draw game over screen with two buttons
- local function drawGameOver()
- monitor.setBackgroundColor(colors.black)
- monitor.clear()
- monitor.setCursorPos(math.floor(width/2) - 4, math.floor(height/4))
- monitor.setTextColor(colors.yellow)
- monitor.write("GAME OVER!")
- monitor.setCursorPos(math.floor(width/2) - 7, math.floor(height/4) + 2)
- monitor.setTextColor(colors.white)
- monitor.write("Final Score: " .. gameState.score)
- -- Continue button (with increased difficulty)
- local continueButtonWidth = 16
- local buttonHeight = 3
- local continueButtonX = math.floor(width/2) - math.floor(continueButtonWidth/2)
- local continueButtonY = math.floor(height/2)
- drawButton(continueButtonX, continueButtonY, continueButtonWidth, buttonHeight,
- "Continue (Lvl " .. math.min(5, gameState.difficulty + 1) .. ")",
- colors.blue, colors.white)
- -- New Game button
- local newGameButtonWidth = 16
- local newGameButtonX = math.floor(width/2) - math.floor(newGameButtonWidth/2)
- local newGameButtonY = continueButtonY + buttonHeight + 2
- drawButton(newGameButtonX, newGameButtonY, newGameButtonWidth, buttonHeight,
- "New Game (Lvl 1)",
- colors.green, colors.white)
- return {
- continueButton = {
- x = continueButtonX,
- y = continueButtonY,
- width = continueButtonWidth,
- height = buttonHeight
- },
- newGameButton = {
- x = newGameButtonX,
- y = newGameButtonY,
- width = newGameButtonWidth,
- height = buttonHeight
- }
- }
- end
- -- Spawn a new mole
- local function spawnMole()
- if #gameState.activeMoles >= MAX_ACTIVE_MOLES then return end
- -- Find an empty hole
- local attempts = 0
- while attempts < 20 do
- local x = math.random(1, GRID_WIDTH)
- local y = math.random(1, GRID_HEIGHT)
- if not grid[x][y].active then
- grid[x][y].active = true
- grid[x][y].timeActive = 0
- table.insert(gameState.activeMoles, {x=x, y=y})
- gameState.lastSpawnTime = os.epoch("local") / 1000
- break
- end
- attempts = attempts + 1
- end
- end
- -- Update moles (make them disappear after a while)
- local function updateMoles()
- local i = 1
- while i <= #gameState.activeMoles do
- local mole = gameState.activeMoles[i]
- grid[mole.x][mole.y].timeActive = grid[mole.x][mole.y].timeActive + 1
- -- Mole goes back in hole after some time (slower at lower difficulties)
- if grid[mole.x][mole.y].timeActive > 25 - gameState.difficulty*2 then
- grid[mole.x][mole.y].active = false
- table.remove(gameState.activeMoles, i)
- else
- i = i + 1
- end
- end
- end
- -- Handle player touch during gameplay
- local function handleGameTouch(x, y)
- -- Handle whacking moles
- for gx = 1, GRID_WIDTH do
- for gy = 1, GRID_HEIGHT do
- local cell = grid[gx][gy]
- -- Check if touch is within this cell
- if isInside(x, y, cell.x, cell.y, cell.width, cell.height) then
- -- If there's a mole, whack it!
- if cell.active then
- cell.active = false
- gameState.score = gameState.score + 1
- -- Remove from active moles
- for i, mole in ipairs(gameState.activeMoles) do
- if mole.x == gx and mole.y == gy then
- table.remove(gameState.activeMoles, i)
- break
- end
- end
- -- Increase difficulty more slowly (every 7 points)
- -- And cap at a lower maximum (5 instead of 6)
- gameState.difficulty = math.min(5, 1 + math.floor(gameState.score / 7))
- end
- end
- end
- end
- end
- -- Game loop
- local gameOverButtons = nil
- while true do
- if gameState.isGameOver then
- if not gameOverButtons then
- gameOverButtons = drawGameOver()
- end
- -- Check for touch events on game over screen
- local event, side, touchX, touchY = os.pullEvent("monitor_touch")
- if isInside(touchX, touchY,
- gameOverButtons.continueButton.x,
- gameOverButtons.continueButton.y,
- gameOverButtons.continueButton.width,
- gameOverButtons.continueButton.height) then
- -- Continue with increased difficulty
- return "continue", gameState.score, math.min(5, gameState.difficulty + 1)
- elseif isInside(touchX, touchY,
- gameOverButtons.newGameButton.x,
- gameOverButtons.newGameButton.y,
- gameOverButtons.newGameButton.width,
- gameOverButtons.newGameButton.height) then
- -- Start a new game
- return "new", 0, 1
- end
- else
- -- Update time
- local currentTime = os.epoch("local") / 1000
- gameState.timeLeft = math.max(0, math.floor(GAME_DURATION - (currentTime - gameState.startTime)))
- -- Check if time's up
- if gameState.timeLeft <= 0 then
- gameState.isGameOver = true
- else
- -- Spawn moles at a reasonable rate based on difficulty
- local timeSinceLastSpawn = currentTime - gameState.lastSpawnTime
- local spawnDelay = math.max(2.0, 3.5 - (gameState.difficulty * 0.25))
- if timeSinceLastSpawn > spawnDelay and #gameState.activeMoles < MAX_ACTIVE_MOLES then
- spawnMole()
- end
- -- Update moles
- updateMoles()
- -- Draw game
- drawGame()
- end
- -- Check for touch events during gameplay (non-blocking)
- local timer = os.startTimer(0.1)
- local event, param1, param2, param3 = os.pullEvent()
- if event == "monitor_touch" then
- local side, touchX, touchY = param1, param2, param3
- handleGameTouch(touchX, touchY)
- end
- end
- end
- end
- -- Main program loop
- local function main()
- while true do
- -- Show welcome screen
- local welcomeButtons = drawWelcomeScreen()
- -- Wait for player to press start
- while true do
- local event, side, touchX, touchY = os.pullEvent("monitor_touch")
- if isInside(touchX, touchY,
- welcomeButtons.startButton.x,
- welcomeButtons.startButton.y,
- welcomeButtons.startButton.width,
- welcomeButtons.startButton.height) then
- break
- end
- end
- -- Start the first game
- local gameMode, score, difficulty = "new", 0, 1
- -- Game loop - handles multiple games
- while true do
- gameMode, score, difficulty = playGame(gameMode == "continue", score, difficulty)
- if gameMode == "new" then
- -- If player chose "New Game", go back to welcome screen
- break
- end
- -- If player chose "Continue", we'll loop back to playGame
- end
- end
- end
- -- Create startup file to run this program automatically
- local function createStartupFile()
- local startupPath = "/startup.lua"
- local file = fs.open(startupPath, "w")
- if file then
- file.write('shell.run("whackamole")')
- file.close()
- print("Created startup file to auto-run the game")
- else
- print("Failed to create startup file")
- end
- end
- -- Create the startup file when this program is first run
- if not fs.exists("/startup.lua") then
- createStartupFile()
- end
- -- Start the main program
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement