Advertisement
Tag365

Breakout Game

Jan 6th, 2016
314
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 17.56 KB | None | 0 0
  1. -- Set up local variables
  2. local args = {...}
  3. local sub = string.sub
  4. local width, height = term.getSize()
  5. local bricks, balls, paddle
  6.  
  7. local messages = {
  8.     "Use the keyboard or mouse to move the paddle.",
  9.     "To start your turn click or press enter.",
  10.     "To pause the game press 'p'.",
  11.     "The goal is to break all the bricks using the ball.",
  12.     "The ball will bounce off of bricks and the paddle.",
  13.     "You lose a turn if the balls fall below the paddle.",
  14.     "After the last turn ends the game is over.",
  15. }
  16.  
  17. local damage = {
  18.     ".",
  19.     ":",
  20.     "|",
  21.     "&",
  22. }
  23.  
  24. local game = {}
  25. local state = {
  26.     gameRunning = true,
  27.     gamePaused = false,
  28.     turnStarted = false,
  29.    
  30.     turnsLeft = 4,
  31.     currentTurn = 1,
  32.     level = args[1] or 1,
  33.     score = 0,
  34.    
  35.     wantedPaddlePositionX = math.floor(width*.5),
  36. }
  37.  
  38. local powerUps
  39.  
  40. -- Vector2 class --
  41. local Vector2 = {}
  42. do
  43.     Vector2._index = function(self, key)
  44.         if key == "x" or key == "y" then
  45.             return self[key]
  46.         end
  47.         return Vector2[key]
  48.     end
  49.     local pcall, type, tonumber, setmetatable = pcall, type, tonumber, setmetatable
  50.     local sin, cos, rad, max = math.sin, math.cos, math.rad, math.max
  51.  
  52.     local new = function(X, Y)
  53.         if not pcall(tonumber, X) then
  54.             error("bad argument #1 to 'new' (number expected, got "..type(X)..")", 2)
  55.         end
  56.         if not pcall(tonumber, Y) then
  57.             error("bad argument #2 to 'new' (number expected, got "..type(Y)..")", 2)
  58.         end
  59.         return setmetatable({X = tonumber(X), Y = tonumber(Y)}, Vector2)
  60.     end
  61.     local newFromAngleInDegrees = function(Degrees, Scale)
  62.         local radians = rad(Degrees)
  63.         return setmetatable({X = cos(radians)*Scale, Y = sin(radians)*Scale}, Vector2)
  64.     end
  65.     local newFromAngleInRadians = function(Radians, Scale)
  66.         return setmetatable({X = cos(Radians)*Scale, Y = sin(Radians)*Scale}, Vector2)
  67.     end
  68.     local linearInpoleration = function(obj1, obj2, percent)
  69.         return obj1 + (obj2 - obj1)*percent
  70.     end
  71.     local unit = function(self)
  72.         local maximum = max(self.X, self.Y)
  73.         return setmetatable({X = self.X/maximum, X = self.Y/maximum}, Vector2)
  74.     end
  75.     Vector2.new = new
  76.     Vector2.Lerp = linearInpoleration
  77.     Vector2.Unit = unit
  78.     Vector2.__unm = function(self) return setmetatable({X = -self.X, Y = -self.Y}, Vector2) end
  79.     Vector2.__mod = function(obj1, obj2)
  80.         if type(obj1) == "table" and type(obj2) == "table" then
  81.             return setmetatable({X = obj1.X % obj2.X, Y = obj1.Y % obj2.Y}, Vector2)
  82.         end
  83.         if type(obj1) == "table" then
  84.             return setmetatable({X = obj1.X % obj2, Y = obj1.Y % obj2}, Vector2)
  85.         elseif type(obj2) == "table" then
  86.             return setmetatable({X = obj1 % obj2.X, Y = obj1 % obj2.Y}, Vector2)
  87.         end
  88.     end
  89.     Vector2.__div = function(obj1, obj2)
  90.         if type(obj1) == "table" and type(obj2) == "table" then
  91.             return setmetatable({X = obj1.X / obj2.X, Y = obj1.Y / obj2.Y}, Vector2)
  92.         end
  93.         if type(obj1) == "table" then
  94.             return setmetatable({X = obj1.X / obj2, Y = obj1.Y / obj2}, Vector2)
  95.         elseif type(obj2) == "table" then
  96.             return setmetatable({X = obj1 / obj2.X, Y = obj1 / obj2.Y}, Vector2)
  97.         end
  98.     end
  99.     Vector2.__mul = function(obj1, obj2)
  100.         if type(obj1) == "table" and type(obj2) == "table" then
  101.             return setmetatable({X = obj1.X * obj2.X, Y = obj1.Y * obj2.Y}, Vector2)
  102.         end
  103.         if type(obj1) == "table" then
  104.             return setmetatable({X = obj1.X * obj2, Y = obj1.Y * obj2}, Vector2)
  105.         elseif type(obj2) == "table" then
  106.             return setmetatable({X = obj1 * obj2.X, Y = obj1 * obj2.Y}, Vector2)
  107.         end
  108.     end
  109.     Vector2.__sub = function(obj1, obj2)
  110.         if type(obj1) == "table" and type(obj2) == "table" then
  111.             return setmetatable({X = obj1.X - obj2.X, Y = obj1.Y - obj2.Y}, Vector2)
  112.         end
  113.         if type(obj1) == "table" then
  114.             return setmetatable({X = obj1.X - obj2, Y = obj1.Y - obj2}, Vector2)
  115.         elseif type(obj2) == "table" then
  116.             return setmetatable({X = obj1 - obj2.X, Y = obj1 - obj2.Y}, Vector2)
  117.         end
  118.     end
  119.     Vector2.__add = function(obj1, obj2)
  120.         if type(obj1) == "table" and type(obj2) == "table" then
  121.             return setmetatable({X = obj1.X + obj2.X, Y = obj1.Y + obj2.Y}, Vector2)
  122.         end
  123.         if type(obj1) == "table" then
  124.             return setmetatable({X = obj1.X + obj2, Y = obj1.Y + obj2}, Vector2)
  125.         elseif type(obj2) == "table" then
  126.             return setmetatable({X = obj1 + obj2.X, Y = obj1 + obj2.Y}, Vector2)
  127.         end
  128.     end
  129.  
  130.     local epsilon = 0.0005
  131.  
  132.     Vector2.__eq = function(obj1, obj2)
  133.         if type(obj1) == "table" and type(obj2) == "table" then
  134.             return math.abs((obj1.X or obj1[1]) - (obj2.X or obj2[1])) < epsilon
  135.             and math.abs((obj1.Y or obj1[2]) - (obj2.Y or obj2[2])) < epsilon
  136.         end
  137.         return false
  138.     end
  139.     Vector2.__lt = function(obj1, obj2)
  140.         if type(obj1) == "table" and type(obj2) == "table" then
  141.             return (obj1.X or obj1[1] < obj2.X or obj2[1]) and (obj1.Y or obj1[2] < obj2.Y or obj2[2])
  142.         end
  143.         return false
  144.     end
  145.     Vector2.__le = function(obj1, obj2)
  146.         if type(obj1) == "table" and type(obj2) == "table" then
  147.             return (obj1.X or obj1[1] <= obj2.X or obj2[1]) and (obj1.Y or obj1[2] <= obj2.Y or obj2[2])
  148.         end
  149.         return false
  150.     end
  151.  
  152.     Vector2.__tostring = function(self)
  153.         return (self.X or 0)..", "..(self.Y or 0)
  154.     end
  155. end
  156.  
  157. -- Set up colors --
  158. local tColorLookup = {}
  159. for n=1, 16 do
  160.     tColorLookup[ string.byte( "0123456789abcdef",n,n ) ] = 2^(n-1)
  161. end
  162.  
  163. local tColorToString = {}
  164. for n=1, 16 do
  165.     tColorToString[ 2^(n-1) ] = string.sub( "0123456789abcdef",n,n )
  166. end
  167.  
  168. local bgColor = colors.black
  169. local ballColor = colors.blue
  170. local paddleColor = colors.white
  171. local brickColors = {}
  172.  
  173. -- Set the brick colors
  174. if term.isColor() then
  175.     brickColors = {
  176.         colors.red,
  177.         colors.brown,
  178.         colors.gray,
  179.     }
  180. elseif term.blit then
  181.     brickColors = {
  182.         colors.gray,
  183.         colors.lightGray,
  184.     }
  185.     ballColor = colors.white
  186. else
  187.     brickColors = {colors.white}
  188.     ballColor = colors.white
  189. end
  190.  
  191. -- Brick class --
  192. local Brick = {}
  193. Brick.__index = Brick
  194.  
  195. -- Creates a new brick.
  196. function Brick.new(Position, Size, Color, BrickID)
  197.     local self = setmetatable({}, Brick)
  198.    
  199.     self.Position = Position
  200.     self.Size = Size
  201.     self.Color = Color
  202.     --self.Text = " "
  203.     self.IsBrick = true
  204.     self.BrickID = BrickID
  205.    
  206.     -- Brick health
  207.     if state.level >= 4 then
  208.         self.Health = 1 + math.random(0, math.floor((state.level - 1)/4))
  209.         self.MaxHealth = self.Health
  210.     end
  211.    
  212.     -- Select a random power up.
  213.     for key, powerUp in pairs(powerUps) do
  214.         local selectPowerUp = math.random()
  215.         if state.level >= (powerUp.LevelToStartSpawning or 1) then
  216.             if selectPowerUp <= (powerUp.Chance or .025) then
  217.                 self.PowerUp = powerUp
  218.                 self.Color = powerUp.BrickColor
  219.                 self.Text = powerUp.BrickText
  220.                 break
  221.             end
  222.         end
  223.     end
  224.    
  225.     return self
  226. end
  227.  
  228. -- Draws the brick on to the screen.
  229. function Brick:Draw()
  230.     local str
  231.     if self.Health then
  232.         str = string.rep(self.Text or (damage[math.floor(((self.MaxHealth - self.Health)/self.MaxHealth)*#damage)] or " "), self.Size.X)
  233.     else
  234.         str = string.rep(self.Text or " ", self.Size.X)
  235.     end
  236.     term.setBackgroundColor(self.Color)
  237.     for y = self.Position.Y, self.Position.Y + self.Size.Y - 1 do
  238.         term.setCursorPos(self.Position.X - math.floor(self.Size.X*.5), y)
  239.         term.write(str)
  240.     end
  241. end
  242.  
  243. -- Damages the brick.
  244. function Brick:Damage(ball)
  245.     state.score = state.score + 1
  246.     if self.Health then
  247.         self.Health = self.Health - ball.Strength
  248.         if self.Health <= 0 then
  249.             self:Destroy(ball)
  250.         end
  251.     else
  252.         self:Destroy(ball)
  253.     end
  254. end
  255.  
  256. -- Destroys the brick.
  257. function Brick:Destroy(ball)
  258.     if self.PowerUp then
  259.         self.PowerUp.OnDestroy(self, ball)
  260.     end
  261.    
  262.     bricks[self.BrickID] = nil
  263.     state.score = state.score + 1
  264.    
  265.     -- Check if there are any bricks left.
  266.     local bricksLeft = 0
  267.     for key, value in pairs(bricks) do
  268.         bricksLeft = bricksLeft + 1
  269.         break
  270.     end
  271.    
  272.     if bricksLeft <= 0 then
  273.         game.GoToNextLevel()
  274.     end
  275. end
  276.  
  277. -- Ball class --
  278. local Ball = {}
  279. Ball.__index = Ball
  280.  
  281. -- Creates a new ball.
  282. function Ball.new(Position, BallID)
  283.     local self = setmetatable({}, Ball)
  284.    
  285.     self.Position = Position
  286.     self.Velocity = Vector2.new(0, -1)
  287.     self.Strength = 1
  288.     self.BallID = BallID
  289.    
  290.     return self
  291. end
  292.  
  293. -- Handles collision with other entities.
  294. function Ball:DoCollision(otherItem)
  295.     local objCenter, objWidth = otherItem.Position.X, otherItem.Size.X
  296.    
  297.     local offset = (self.Position.X - objCenter)/objWidth
  298.    
  299.     self.Velocity = Vector2.new(offset, -self.Velocity.Y)
  300.    
  301.     -- If it is a brick then destroy it.
  302.     if otherItem.IsBrick then
  303.         otherItem:Damage(self)
  304.     end
  305. end
  306.  
  307. -- Updates the ball.
  308. function Ball:Update()
  309.     -- Try to collide with the bricks.
  310.     for key, brick in pairs(bricks) do
  311.         if self.Position.X >= math.ceil(brick.Position.X - brick.Size.X*.5) and self.Position.X <= math.floor(brick.Position.X + (brick.Size.X - 1)*.5) then
  312.             if self.Position.Y >= brick.Position.Y and self.Position.Y <= brick.Position.Y + brick.Size.Y then
  313.                 self:DoCollision(brick)
  314.                 break
  315.             end
  316.         end
  317.     end
  318.    
  319.     -- Try to collide with the paddle.
  320.     if self.Position.X >= paddle.Position.X - paddle.Size.X*.5 and self.Position.X <= paddle.Position.X + paddle.Size.X*.5 then
  321.         if self.Position.Y >= paddle.Position.Y and self.Position.Y <= paddle.Position.Y + paddle.Size.Y then
  322.             self:DoCollision(paddle)
  323.         end
  324.     end
  325.    
  326.     -- Try to collide with the wall.
  327.     if self.Position.X <= 1 then
  328.         self.Velocity.X = math.abs(self.Velocity.X)
  329.     elseif self.Position.X >= width then
  330.         self.Velocity.X = -math.abs(self.Velocity.X)
  331.     elseif self.Position.Y <= 1 then
  332.         self.Velocity.Y = math.abs(self.Velocity.Y)
  333.     elseif self.Position.Y > height then
  334.         -- The player lost the ball by letting it touch the bottom of the screen.
  335.         self:Destroy()
  336.         return
  337.     end
  338.    
  339.     -- Shift the ball.
  340.     self.Position = self.Position + self.Velocity
  341. end
  342.  
  343. -- Draws the ball to the screen.
  344. function Ball:Draw()
  345.     term.setCursorPos(self.Position.X, self.Position.Y)
  346.     term.setBackgroundColor(ballColor)
  347.     term.write("#")
  348. end
  349.  
  350. -- Destroys the ball.
  351. function Ball:Destroy()
  352.     table.remove(balls, self.BallID)
  353.    
  354.     for key, ball in ipairs(balls) do
  355.         ball.BallID = key
  356.     end
  357.    
  358.     -- Check if there are any balls left, and if no balls are left then make the player lose a turn.
  359.     local ballsLeft = #balls
  360.    
  361.     if ballsLeft <= 0 then
  362.         game.ReloadLevel(false, true)
  363.     end
  364. end
  365.  
  366. -- Paddle class --
  367. local Paddle = {}
  368. Paddle.__index = Paddle
  369.  
  370. -- Creates a new paddle.
  371. function Paddle.new(Position)
  372.     local self = setmetatable({}, Paddle)
  373.    
  374.     self.Position = Position
  375.     self.Size = Vector2.new(7, 1)
  376.    
  377.     return self
  378. end
  379.  
  380. -- Updates the paddle.
  381. function Paddle:Update()
  382.     -- Move the paddle closer to where the player wants it.
  383.     local offset = (state.wantedPaddlePositionX - self.Position.X)
  384.     if math.abs(offset) > 0.5 then
  385.         self.Position = self.Position + Vector2.new((offset/math.abs(offset)), 0)
  386.     end
  387. end
  388.  
  389. -- Draws the paddle to the screen.
  390. function Paddle:Draw()
  391.     term.setCursorPos(self.Position.X - math.floor(self.Size.X*.5), self.Position.Y)
  392.     term.setBackgroundColor(paddleColor)
  393.     term.write(string.rep(" ", self.Size.X))
  394. end
  395.  
  396. -- Makes the game progress to the next level.
  397. function game.GoToNextLevel()
  398.     sleep(.5)
  399.     state.level = state.level + 1
  400.     game.ReloadLevel(true)
  401. end
  402.  
  403. -- Reloads the level, by resetting the ball and paddle, and also the bricks if requested.
  404. function game.ReloadLevel(ReloadBricks, TurnLost)
  405.     -- Check if we lost a turn.
  406.     if TurnLost then
  407.         state.turnsLeft = state.turnsLeft - 1
  408.         if state.turnsLeft <= 0 then
  409.             state.turnsLeft = 0
  410.             state.gameRunning = false -- End the game.
  411.             return false
  412.         end
  413.         state.currentTurn = state.currentTurn + 1
  414.     end
  415.    
  416.     -- Reload the level.
  417.     state.turnStarted = false
  418.     state.wantedPaddlePositionX = math.floor(width*.5)
  419.    
  420.     -- Reset the paddle.
  421.     paddle = Paddle.new(Vector2.new(math.floor(width*.5), height - 1))
  422.    
  423.     -- Reset the ball.
  424.     balls = {Ball.new(Vector2.new(width*.5, height - 2), 1)}
  425.    
  426.     -- If we need to then reload the bricks as well.
  427.     if ReloadBricks then
  428.         math.randomseed(state.level)
  429.         bricks = {}
  430.         local startPos = width%4
  431.         for y = 1, math.min(math.floor((state.level - 1)*.4) + 4, height - 5) do
  432.             for x = startPos, -startPos + width + 4, 4 do
  433.                 bricks[#bricks + 1] = Brick.new(Vector2.new(x, y), Vector2.new(4, 1), brickColors[(#bricks%#brickColors) + 1], #bricks + 1)
  434.             end
  435.         end
  436.     end
  437. end
  438.  
  439. -- Draws on to the screen.
  440. function game.Draw()
  441.     term.setBackgroundColor(bgColor)
  442.     term.clear()
  443.    
  444.     local topLineBgColors
  445.     if term.blit then
  446.         -- Set up the topLineBgColors for the term.blit operation we will do later.
  447.         topLineBgColors = {}
  448.    
  449.         for x = 1, width do
  450.             topLineBgColors[x] = tColorToString[bgColor]
  451.         end
  452.        
  453.         -- Draw the bricks.
  454.         for key, brick in pairs(bricks) do
  455.             -- If the brick is on the top line, add it to the topLineBgColors table.
  456.             if brick.Position.Y == 1 then
  457.                 local left = brick.Position.X - math.floor(brick.Size.X*.5)
  458.                 local right = brick.Position.X + math.floor(brick.Size.X*.5) - 1
  459.                 for x = left, math.floor(right) do
  460.                     if x >= 1 and x <= width then
  461.                         topLineBgColors[x] = tColorToString[brick.Color]
  462.                     end
  463.                 end
  464.                 if brick.Size.Y > 1 then
  465.                     brick:Draw()
  466.                 end
  467.             else
  468.                 brick:Draw()
  469.             end
  470.         end
  471.     else
  472.         -- Since blit is not available, we simply draw the bricks.
  473.         for key, brick in pairs(bricks) do
  474.             brick:Draw()
  475.         end
  476.     end
  477.    
  478.     -- Draw text on the top line of the terminal if term.blit exists, or just below the paddle if not.
  479.     if term.blit then
  480.         -- Draw the text at the top of the screen.
  481.         local topLineText = string.rep(" ", width)
  482.         local topLineTxtColorString = string.rep("0", width)
  483.         local topLineBGString = table.concat(topLineBgColors, "")
  484.        
  485.         local scoreText = "Score "..state.score
  486.         local levelText = "Level "..state.level
  487.         local turnText = "Turn "..(state.currentTurn).." of "..(state.turnsLeft - 1 + state.currentTurn)
  488.        
  489.         topLineText = sub(scoreText, 1, 12) .. sub(topLineText, #scoreText + 1, 12) .. sub(levelText, 1, 12) .. sub(topLineText, #levelText + 13, 24) .. sub(turnText, 1, width - 24) .. sub(topLineText, #turnText + 25)
  490.        
  491.         term.setCursorPos(1, 1)
  492.         term.blit(topLineText, topLineTxtColorString, topLineBGString)
  493.     elseif (state.currentTurn > 1 or state.level > 1) then
  494.         -- Draw the text at the bottom of the screen.
  495.         term.setBackgroundColor(bgColor)
  496.        
  497.         term.setCursorPos(1, height)
  498.         term.write("Score "..state.score)
  499.        
  500.         term.setCursorPos(13, height)
  501.         term.write("Level "..state.level)
  502.        
  503.         term.setCursorPos(25, height)
  504.         term.write("Turn "..(state.currentTurn).." of " .. (state.turnsLeft - 1 + state.currentTurn))
  505.     end
  506.    
  507.     -- Draw the paddle.
  508.     paddle:Draw()
  509.    
  510.     -- Draw the balls.
  511.     for key, ball in pairs(balls) do
  512.         ball:Draw()
  513.     end
  514.    
  515.     -- Draw help at the bottom of the screen.
  516.     if #messages > 0 then
  517.         if not state.turnStarted and (term.blit or state.currentTurn <= 1 or state.level <= 1) then
  518.             term.setCursorPos(1, height)
  519.             term.write(messages[math.floor(((os.clock()/5)%#messages) + 1)])
  520.         end
  521.     end
  522. end
  523.  
  524. -- Finish the powerUps
  525. powerUps = {
  526.     ["ExtraTurn"] = {
  527.         Name = "Extra Turn",
  528.         --LevelToStartSpawning = 1,
  529.         OnDestroy = function(self, ball)
  530.             state.turnsLeft = state.turnsLeft + 1
  531.         end,
  532.         BrickText = "#",
  533.         BrickColor = colors.blue,
  534.     },
  535.     ["DoubleBall"] = {
  536.         Name = "Double Ball",
  537.         --LevelToStartSpawning = 2,
  538.         OnDestroy = function(self, ball)
  539.             balls[#balls + 1] = Ball.new(self.Position, #balls + 1)
  540.         end,
  541.         BrickText = "2",
  542.         BrickColor = colors.blue,
  543.     },
  544.     ["SuperBall"] = {
  545.         Name = "Super Ball",
  546.         --LevelToStartSpawning = 5,
  547.         OnDestroy = function(self, ball)
  548.             ball.Strength = ball.Strength + 1
  549.         end,
  550.         BrickText = "S",
  551.         BrickColor = colors.red,
  552.     },
  553.     ["WiderPaddle"] = {
  554.         Name = "Wide Paddle",
  555.         --LevelToStartSpawning = 13,
  556.         OnDestroy = function(self, ball)
  557.             paddle.Size.X = paddle.Size.X + 6
  558.         end,
  559.         BrickText = "W",
  560.         BrickColor = colors.green,
  561.     },
  562. }
  563.  
  564. -- Load the level.
  565. game.ReloadLevel(true)
  566. game.Draw()
  567.  
  568. -- Game loop --
  569. local timerUsed = os.startTimer(.05) -- Start a timer to make the game continue on its own
  570. while state.gameRunning do
  571.     -- Handle events.
  572.     local event, arg1, arg2, arg3, arg4, arg5 = os.pullEventRaw()
  573.     if event == "key" then
  574.         if arg1 == keys.left or arg1 == keys.a then
  575.             state.wantedPaddlePositionX = math.max(state.wantedPaddlePositionX - 1, math.floor(paddle.Size.X*.5))
  576.         elseif arg1 == keys.right or arg1 == keys.d then
  577.             state.wantedPaddlePositionX = math.min(state.wantedPaddlePositionX + 1, math.ceil(width - paddle.Size.X*.5))
  578.         elseif arg1 == keys.space or arg1 == keys.enter then
  579.             state.turnStarted = true
  580.         elseif arg1 == keys.p or arg1 == keys.esc then
  581.             state.gamePaused = not state.gamePaused
  582.         end
  583.         if not state.turnStarted then
  584.             for key, ball in pairs(balls) do
  585.                 ball.Position = paddle.Position + Vector2.new(0, -1)
  586.             end
  587.         end
  588.     elseif event == "mouse_click" and arg1 == 1 then
  589.         state.turnStarted = true
  590.         state.wantedPaddlePositionX = math.max(math.min(arg2, math.ceil(width - paddle.Size.X*.5)), math.floor(paddle.Size.X*.5))
  591.     elseif event == "timer" and arg1 == timerUsed then
  592.         -- Start updating.
  593.         if not state.gamePaused then
  594.             paddle:Update()
  595.             if state.turnStarted then
  596.                 for key = 1, #balls do
  597.                     if balls[key] then
  598.                         balls[key]:Update()
  599.                     end
  600.                 end
  601.             else
  602.                 for key, ball in pairs(balls) do
  603.                     ball.Position = paddle.Position + Vector2.new(0, -1)
  604.                 end
  605.             end
  606.         end
  607.        
  608.         -- Draw to the screen.
  609.         game.Draw()
  610.        
  611.         timerUsed = os.startTimer(.05) -- Start a timer to make the game continue on its own again
  612.     elseif event == "terminate" then
  613.         state.gameRunning = false
  614.     end
  615. end
  616.  
  617. -- The game has ended.
  618. term.setBackgroundColor(colors.black)
  619. term.setTextColor(colors.white)
  620. term.setCursorPos(1, 1)
  621. term.clear()
  622.  
  623. if state.turnsLeft <= 0 then
  624.     print("Game over! No more turns left.")
  625. end
  626. print("You obtained a score of "..state.score.." points.")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement