SHOW:
|
|
- or go back to the newest paste.
| 1 | -- +---------------------+------------+---------------------+ | |
| 2 | -- | ## # # | | ## # ## | | |
| 3 | -- | ## # ## | BBTetris | ## ## # | | |
| 4 | -- | ## # | #### | # # | | |
| 5 | -- +---------------------+------------+---------------------+ | |
| 6 | ||
| 7 | local version = "Version 1.0.6" | |
| 8 | ||
| 9 | -- Yet another version of Tetris, by Jeffrey Alexander (aka Bomb Bloke). | |
| 10 | -- Heavily based on the old "Brick Game"s you may've once seen. | |
| 11 | -- http://www.computercraft.info/forums2/index.php?/topic/15878-bbtetris | |
| 12 | -- Automatically goes into monitor mode, added by Hannez04 | |
| 13 | ||
| 14 | ||
| 15 | --------------------------------------------- | |
| 16 | ------------Variable Declarations------------ | |
| 17 | --------------------------------------------- | |
| 18 | ||
| 19 | -- Seven regular blocks, six "advanced" blocks, three "trick" blocks. | |
| 20 | local block = {
| |
| 21 | {{1,1,0},{0,1,1}},{{0,1,0},{0,1,0},{0,1,0},{0,1,0}},{{0,1,1},{1,1,0}},{{1,1},{1,1}},{{1,1,1},{0,1,0},
| |
| 22 | {0,0,0}},{{1,1,1},{0,0,1}},{{1,1,1},{1,0,0}},{{1,1,0},{0,1,0},{0,1,1}},{{1,1},{0,1}},{{1,0,0},{1,1,1},
| |
| 23 | {1,0,0}},{{0,1,0},{1,1,1},{0,1,0}},{{1},{1}},{{1,1,1},{1,0,1}},{{1}},{{1},{1}},{{1},{1},{1}}}
| |
| 24 | ||
| 25 | -- The menu numerals. Eight in all. | |
| 26 | local number = {
| |
| 27 | {{5,1},{4,1,1},{5,1},{5,1},{5,1},{5,1},{4,1,1,1}},{{4,1,1,1},{3,1,0,0,0,1},{7,1},{6,1},{5,1},{4,1},
| |
| 28 | {3,1,1,1,1,1}},{{4,1,1,1},{3,1,0,0,0,1},{7,1},{4,1,1,1},{7,1},{3,1,0,0,0,1},{4,1,1,1}},{{6,1},{5,1,1},
| |
| 29 | {4,1,0,1},{3,1,0,0,1},{3,1,0,0,1},{3,1,1,1,1,1},{6,1}},{{3,1,1,1,1,1},{3,1},{3,1,1,1,1},{7,1},{7,1},
| |
| 30 | {3,1,0,0,0,1},{4,1,1,1}},{{4,1,1,1},{3,1,0,0,0,1},{3,1},{3,1,1,1,1},{3,1,0,0,0,1},{3,1,0,0,0,1},
| |
| 31 | {4,1,1,1}},{{3,1,1,1,1,1},{7,1},{6,1},{5,1},{5,1},{4,1},{4,1}},{{4,1,1,1},{3,1,0,0,0,1},{3,1,0,0,0,1},
| |
| 32 | {4,1,1,1},{3,1,0,0,0,1},{3,1,0,0,0,1},{4,1,1,1}}}
| |
| 33 | ||
| 34 | local gamemode, speed, level, running, grid, saves, canSave, playMusic, pocket, depth = 1, 0, 0, true, {}, {}, true, true
| |
| 35 | local highScore, screenx, screeny, myEvent, mon, OGeventPuller, skipIntro, skipMonitor, defaultMonitor | |
| 36 | ||
| 37 | local musicFile = "moarp/songs/Tetris A Theme.nbs" | |
| 38 | ||
| 39 | --------------------------------------------- | |
| 40 | ------------Function Declarations------------ | |
| 41 | --------------------------------------------- | |
| 42 | ||
| 43 | -- Return to shell. | |
| 44 | local function exitGame(erroring) | |
| 45 | if canSave then | |
| 46 | myEvent = fs.open(shell.resolve(".").."\\bbtetris.dat", "w")
| |
| 47 | myEvent.writeLine("Save data file for Bomb Bloke's Tetris game.")
| |
| 48 | myEvent.writeLine(string.gsub(textutils.serialize(highScore),"\n%s*","")) | |
| 49 | myEvent.writeLine(string.gsub(textutils.serialize(saves),"\n%s*","")) | |
| 50 | myEvent.close() | |
| 51 | end | |
| 52 | ||
| 53 | term.setBackgroundColor(colours.black) | |
| 54 | term.setTextColor(colours.white) | |
| 55 | ||
| 56 | if mon then | |
| 57 | term.clear() | |
| 58 | if term.restore then term.restore() else term.redirect(mon.restoreTo) end | |
| 59 | end | |
| 60 | ||
| 61 | if note then os.unloadAPI("note") end
| |
| 62 | ||
| 63 | term.clear() | |
| 64 | term.setCursorPos(1,1) | |
| 65 | if erroring then print(erroring.."\n") end | |
| 66 | print("Thanks for playing!")
| |
| 67 | ||
| 68 | if (shell.resolve(".") == "disk") and not fs.exists("\\bbtetris") then
| |
| 69 | print("\nIf you wish to copy me to your internal drive (for play without the disk - this allows saving of score data etc), type:\n\ncp \\disk\\bbtetris \\bbtetris\n")
| |
| 70 | end | |
| 71 | ||
| 72 | os.pullEvent = OGeventPuller | |
| 73 | error() | |
| 74 | end | |
| 75 | ||
| 76 | -- Writes regular text at the specified location on the screen. | |
| 77 | local function writeAt(text, x , y) | |
| 78 | term.setBackgroundColor(colours.black) | |
| 79 | term.setTextColor(colours.white) | |
| 80 | term.setCursorPos(screenx+x,screeny+y) | |
| 81 | term.write(text) | |
| 82 | end | |
| 83 | ||
| 84 | -- Returns whether a given event was a touch event this program should listen to. | |
| 85 | local function touchedMe() | |
| 86 | if myEvent[1] == "mouse_click" then return true | |
| 87 | elseif myEvent[1] ~= "monitor_touch" or not mon then return false | |
| 88 | else return mon.side == myEvent[2] end | |
| 89 | end | |
| 90 | ||
| 91 | -- Returns whether one of a given set of keys was pressed. | |
| 92 | local function pressedKey(...) | |
| 93 | if myEvent[1] ~= "key" then return false end | |
| 94 | for i=1,#arg do if arg[i] == myEvent[2] then return true end end | |
| 95 | return false | |
| 96 | end | |
| 97 | ||
| 98 | -- Returns whether a click was performed at a given location. | |
| 99 | -- If two parameters are passed, it checks to see if x is [1] and y is [2]. | |
| 100 | -- If three parameters are passed, it checks to see if x is [1] and y is between [2]/[3] (non-inclusive). | |
| 101 | -- If four paramaters are passed, it checks to see if x is between [1]/[2] and y is between [3]/[4] (non-inclusive). | |
| 102 | local function clickedAt(...) | |
| 103 | if not touchedMe() then return false end | |
| 104 | if #arg == 2 then return (myEvent[3] == arg[1]+screenx and myEvent[4] == arg[2]+screeny) | |
| 105 | elseif #arg == 3 then return (myEvent[3] == arg[1]+screenx and myEvent[4] > arg[2]+screeny and myEvent[4] < arg[3]+screeny) | |
| 106 | else return (myEvent[3] > arg[1]+screenx and myEvent[3] < arg[2]+screenx and myEvent[4] > arg[3]+screeny and myEvent[4] < arg[4]+screeny) end | |
| 107 | end | |
| 108 | ||
| 109 | -- Ensures the wrapped monitor is suitable for play. | |
| 110 | local function enforceScreenSize() | |
| 111 | term.setBackgroundColor(colours.black) | |
| 112 | term.setTextColor(colours.white) | |
| 113 | ||
| 114 | while true do | |
| 115 | local scale = 5 | |
| 116 | mon.setTextScale(scale) | |
| 117 | screenx,screeny = term.getSize() | |
| 118 | ||
| 119 | term.clear() | |
| 120 | term.setCursorPos(1,1) | |
| 121 | ||
| 122 | while (screenx < 50 or screeny < (depth or 19)) and scale > 0.5 do | |
| 123 | scale = scale - 0.5 | |
| 124 | mon.setTextScale(scale) | |
| 125 | screenx,screeny = term.getSize() | |
| 126 | end | |
| 127 | ||
| 128 | if screenx > 49 and screeny > (depth or 19) - 1 then | |
| 129 | screenx,screeny = math.floor(screenx/2)-10, math.floor(screeny/2)-9 | |
| 130 | sleep(0.1) | |
| 131 | return | |
| 132 | else print("Make this display out of at least three by two monitor blocks, or tap me to quit.") end
| |
| 133 | ||
| 134 | while true do | |
| 135 | myEvent = {os.pullEvent()}
| |
| 136 | ||
| 137 | if myEvent[1] == "monitor_resize" then break | |
| 138 | elseif myEvent[1] == "key" or touchedMe() or myEvent[1] == "terminate" then exitGame() | |
| 139 | elseif myEvent[1] == "peripheral_detach" and mon then | |
| 140 | if myEvent[2] == mon.side then exitGame("I've lost my monitor - your turtle didn't mine it, I hope?") end
| |
| 141 | elseif myEvent[1] == "musicFinished" then os.queueEvent("musicPlay",musicFile) end
| |
| 142 | end | |
| 143 | end | |
| 144 | end | |
| 145 | ||
| 146 | -- Draws the frame around the playing area, along with other static stuff. | |
| 147 | local function drawBorder() | |
| 148 | term.setBackgroundColor(colours.black) | |
| 149 | term.clear() | |
| 150 | ||
| 151 | writeAt("High",14,11)
| |
| 152 | writeAt("Level",14,14)
| |
| 153 | writeAt("Speed",14,17)
| |
| 154 | ||
| 155 | if not pocket then | |
| 156 | writeAt("[H]elp",-6,2)
| |
| 157 | writeAt("[ ] Advanced",22,14)
| |
| 158 | writeAt("[ ] Tricks",22,16)
| |
| 159 | writeAt("[ ] Quota",22,18)
| |
| 160 | end | |
| 161 | ||
| 162 | writeAt("[Q]uit",pocket and 21 or 22,2)
| |
| 163 | ||
| 164 | term.setBackgroundColor(term.isColor() and colours.yellow or colours.white) | |
| 165 | term.setTextColor(term.isColor() and colours.lightGrey or colours.black) | |
| 166 | ||
| 167 | term.setCursorPos(screenx+1,screeny) | |
| 168 | term.write(string.rep("L",20))
| |
| 169 | term.setCursorPos(screenx+1,screeny+depth+1) | |
| 170 | term.write(string.rep("L",20))
| |
| 171 | term.setCursorPos(screenx+13,screeny+6) | |
| 172 | term.write(string.rep("L",7))
| |
| 173 | ||
| 174 | for i=1,depth do | |
| 175 | term.setCursorPos(screenx+1,screeny+i) | |
| 176 | term.write("L")
| |
| 177 | term.setCursorPos(screenx+12,screeny+i) | |
| 178 | term.write("L")
| |
| 179 | term.setCursorPos(screenx+20,screeny+i) | |
| 180 | term.write("L")
| |
| 181 | end | |
| 182 | end | |
| 183 | ||
| 184 | -- Draws the big numbers indicating the game mode on the main menu (plus associated data). | |
| 185 | local function drawNumeral() | |
| 186 | term.setTextColor(term.isColor() and colours.lightGrey or colours.black) | |
| 187 | ||
| 188 | for i=1,7 do | |
| 189 | term.setCursorPos(screenx+2,screeny+i+6) | |
| 190 | term.setBackgroundColor(colours.black) | |
| 191 | term.write(string.rep(" ",10))
| |
| 192 | term.setBackgroundColor(term.isColor() and colours.blue or colours.white) | |
| 193 | ||
| 194 | for j=2,#number[gamemode][i] do if number[gamemode][i][j] == 1 then | |
| 195 | term.setCursorPos(screenx+number[gamemode][i][1]+j,screeny+i+6) | |
| 196 | term.write("L")
| |
| 197 | end end | |
| 198 | end | |
| 199 | ||
| 200 | term.setBackgroundColor(colours.black) | |
| 201 | term.setTextColor(term.isColor() and colours.green or colours.white) | |
| 202 | ||
| 203 | if not pocket then for i=0,2 do | |
| 204 | term.setCursorPos(screenx+23,screeny+14+i*2) | |
| 205 | term.write(bit.band(gamemode-1,bit.blshift(1,i))==bit.blshift(1,i) and "O" or " ") | |
| 206 | end end | |
| 207 | ||
| 208 | writeAt(string.rep(" ",6-#tostring(highScore[gamemode]))..tostring(highScore[gamemode]),13,12)
| |
| 209 | end | |
| 210 | ||
| 211 | -- Fill the grid with random blocks according to the chosen level. | |
| 212 | local function fillGrid() | |
| 213 | term.setBackgroundColor(bit.band(gamemode-1,4)==4 and colours.red or colours.white) | |
| 214 | term.setTextColor(term.isColor() and colours.lightGrey or colours.black) | |
| 215 | ||
| 216 | for i=1,level+(bit.band(gamemode-1,4)==4 and 1 or 0) do | |
| 217 | grid[i] = {}
| |
| 218 | for j=1,10 do if math.random(2) > 1 then | |
| 219 | term.setCursorPos(screenx+j+1,screeny+depth+1-i) | |
| 220 | term.write("L")
| |
| 221 | grid[i][j] = bit.band(gamemode-1,4)==4 and 14 or 32 | |
| 222 | end end | |
| 223 | end | |
| 224 | ||
| 225 | if bit.band(gamemode-1,4)==4 then for i=level+2,depth do grid[i] = {} end end
| |
| 226 | end | |
| 227 | ||
| 228 | -- Do the game over animation. | |
| 229 | local function gameover() | |
| 230 | term.setBackgroundColor(term.isColor() and colours.black or colours.white) | |
| 231 | term.setTextColor(term.isColor() and colours.lightGrey or colours.black) | |
| 232 | for i=depth,1,-1 do | |
| 233 | term.setCursorPos(screenx+2,screeny+i) | |
| 234 | term.write(string.rep("L",10))
| |
| 235 | blockTimer = os.startTimer(0.1) | |
| 236 | while myEvent[2] ~= blockTimer do myEvent = {os.pullEvent("timer")} end
| |
| 237 | end | |
| 238 | ||
| 239 | term.setBackgroundColor(colours.black) | |
| 240 | for i=1,depth do | |
| 241 | term.setCursorPos(screenx+2,screeny+i) | |
| 242 | term.write(string.rep(" ",10))
| |
| 243 | blockTimer = os.startTimer(0.1) | |
| 244 | while myEvent[2] ~= blockTimer do myEvent = {os.pullEvent("timer")} end
| |
| 245 | end | |
| 246 | end | |
| 247 | ||
| 248 | -- Renders the block (or clears that area of the screen if not "drawing"). | |
| 249 | local function drawBlock(thisBlock,rotation,xpos,ypos,drawing,flicker) | |
| 250 | if thisBlock > 13 and not drawing then | |
| 251 | term.setTextColor(term.isColor() and colours.lightGrey or colours.black) | |
| 252 | for y=1,#block[thisBlock] do | |
| 253 | term.setCursorPos(screenx+xpos+1,screeny+ypos+y-1) | |
| 254 | if grid[depth+2-ypos-y][xpos] ~= nil then | |
| 255 | term.setBackgroundColor(term.isColor() and bit.blshift(1,grid[depth+1-ypos][xpos]) or colours.white) | |
| 256 | term.write("L")
| |
| 257 | else | |
| 258 | term.setBackgroundColor(colours.black) | |
| 259 | term.write(" ")
| |
| 260 | end | |
| 261 | end | |
| 262 | return | |
| 263 | end | |
| 264 | ||
| 265 | if drawing and thisBlock > 13 then | |
| 266 | term.setBackgroundColor(term.isColor() and (flicker and colours.white or colours.black) or (flicker and colours.black or colours.white)) | |
| 267 | else | |
| 268 | term.setBackgroundColor(drawing and (term.isColor() and bit.blshift(1,thisBlock) or colours.white) or colours.black) | |
| 269 | end | |
| 270 | ||
| 271 | term.setTextColor(term.isColor() and colours.lightGrey or (flicker and colours.white or colours.black)) | |
| 272 | ||
| 273 | for y=1,#block[thisBlock] do for x=1,#block[thisBlock][1] do if block[thisBlock][y][x] == 1 then | |
| 274 | if rotation == 0 then | |
| 275 | term.setCursorPos(screenx+xpos+x,screeny+ypos+y-1) | |
| 276 | elseif rotation == 1 then | |
| 277 | term.setCursorPos(screenx+xpos+#block[thisBlock]+1-y,screeny+ypos+x-1) | |
| 278 | elseif rotation == 2 then | |
| 279 | term.setCursorPos(screenx+xpos+#block[thisBlock][1]+1-x,screeny+ypos+#block[thisBlock]-y) | |
| 280 | elseif rotation == 3 then | |
| 281 | term.setCursorPos(screenx+xpos+y,screeny+ypos+#block[thisBlock][1]-x) | |
| 282 | end | |
| 283 | ||
| 284 | term.write(drawing and "L" or " ") | |
| 285 | end end end | |
| 286 | end | |
| 287 | ||
| 288 | -- Returns whether the block can move into the specified position. | |
| 289 | local function checkBlock(thisBlock,rotation,xpos,ypos) | |
| 290 | if thisBlock == 14 then | |
| 291 | if xpos < 1 or xpos > 10 then return false end | |
| 292 | for y = 1,depth+1-ypos do if grid[y][xpos] == nil then return true end end | |
| 293 | return false | |
| 294 | end | |
| 295 | ||
| 296 | local checkX, checkY | |
| 297 | ||
| 298 | for y=1,#block[thisBlock] do for x=1,#block[thisBlock][1] do if block[thisBlock][y][x] == 1 then | |
| 299 | if rotation == 0 then | |
| 300 | checkX, checkY = xpos+x-1, ypos+y-1 | |
| 301 | elseif rotation == 1 then | |
| 302 | checkX, checkY = xpos+#block[thisBlock]-y, ypos+x-1 | |
| 303 | elseif rotation == 2 then | |
| 304 | checkX, checkY = xpos+#block[thisBlock][1]-x, ypos+#block[thisBlock]-y | |
| 305 | elseif rotation == 3 then | |
| 306 | checkX, checkY = xpos+y-1, ypos+#block[thisBlock][1]-x | |
| 307 | end | |
| 308 | ||
| 309 | if checkX < 1 or checkX > 10 or checkY < 1 or checkY > depth or grid[depth+1-checkY][checkX] ~= nil then return false end | |
| 310 | end end end | |
| 311 | ||
| 312 | return true | |
| 313 | end | |
| 314 | ||
| 315 | -- Redraw the game view after a monitor re-size. | |
| 316 | local function redrawGame(score) | |
| 317 | drawBorder() | |
| 318 | ||
| 319 | writeAt("[P]ause",pocket and 21 or 22,4)
| |
| 320 | if note then writeAt("[M]usic",22,6) end
| |
| 321 | writeAt("Next",14,1)
| |
| 322 | writeAt("Score",14,8)
| |
| 323 | writeAt(string.rep(" ",6-#tostring(score))..tostring(score),13,9)
| |
| 324 | writeAt(string.rep(" ",6-#tostring(highScore[gamemode]))..tostring(highScore[gamemode]),13,12)
| |
| 325 | writeAt((level>9 and "" or " ")..tostring(level),17,15) | |
| 326 | writeAt(tostring(speed),18,18) | |
| 327 | ||
| 328 | term.setBackgroundColor(colours.black) | |
| 329 | term.setTextColor(term.isColor() and colours.green or colours.white) | |
| 330 | ||
| 331 | if not pocket then for i=0,2 do | |
| 332 | term.setCursorPos(screenx+23,screeny+14+i*2) | |
| 333 | term.write(bit.band(gamemode-1,bit.blshift(1,i))==bit.blshift(1,i) and "O" or " ") | |
| 334 | end end | |
| 335 | ||
| 336 | term.setTextColor(term.isColor() and colours.lightGrey or colours.black) | |
| 337 | for yy=1,depth do | |
| 338 | term.setCursorPos(screenx+2,screeny+yy) | |
| 339 | for xx=1,10 do if grid[depth+1-yy][xx] ~= nil then | |
| 340 | term.setBackgroundColor(term.isColor() and bit.blshift(1,grid[depth+1-yy][xx]) or colours.white) | |
| 341 | term.write("L")
| |
| 342 | else | |
| 343 | term.setBackgroundColor(colours.black) | |
| 344 | term.write(" ")
| |
| 345 | end end | |
| 346 | end | |
| 347 | end | |
| 348 | ||
| 349 | local function intro() | |
| 350 | local xSize, ySize, temp = term.getSize() | |
| 351 | ||
| 352 | local introBlock = xSize > 49 and | |
| 353 | ||
| 354 | {{11,2,4},{12,2,4},{13,2,4},{14,2,4},{15,2,4},{16,2,4},{17,2,4},{18,2,4},{19,2,4},{20,2,4},{21,2,4},{22,2,4},{23,2,4},
| |
| 355 | {24,2,4},{25,2,4},{8,3,4},{9,3,4},{10,3,4},{26,3,4},{27,3,4},{29,3,11},{5,4,4},{6,4,4},{7,4,4},{13,4,11},{14,4,11},
| |
| 356 | {15,4,11},{16,4,11},{17,4,11},{18,4,11},{29,4,11},{31,4,4},{32,4,4},{33,4,4},{46,4,4},{9,5,11},{10,5,11},{11,5,11},
| |
| 357 | {12,5,11},{14,5,11},{29,5,11},{34,5,4},{44,5,4},{45,5,4},{14,6,11},{25,6,11},{26,6,11},{27,6,11},{29,6,11},{35,6,4},
| |
| 358 | {36,6,4},{37,6,4},{43,6,4},{14,7,11},{20,7,11},{21,7,11},{22,7,11},{23,7,11},{28,7,11},{29,7,11},{38,7,4},{39,7,4},
| |
| 359 | {40,7,4},{41,7,4},{42,7,4},{15,8,11},{19,8,11},{24,8,11},{28,8,11},{30,8,11},{31,8,11},{8,9,14},{9,9,14},{15,9,11},
| |
| 360 | {19,9,11},{20,9,11},{25,9,11},{28,9,11},{45,9,11},{46,9,11},{47,9,11},{4,10,14},{5,10,14},{7,10,14},{10,10,14},
| |
| 361 | {15,10,11},{19,10,11},{21,10,11},{22,10,11},{23,10,11},{24,10,11},{28,10,11},{35,10,11},{36,10,11},{37,10,11},
| |
| 362 | {44,10,11},{48,10,11},{3,11,14},{6,11,14},{8,11,14},{9,11,14},{10,11,14},{11,11,14},{14,11,11},{19,11,11},{29,11,11},
| |
| 363 | {32,11,11},{34,11,11},{38,11,11},{41,11,11},{44,11,11},{4,12,14},{5,12,14},{6,12,14},{9,12,14},{12,12,14},{14,12,11},
| |
| 364 | {20,12,11},{23,12,11},{29,12,11},{33,12,11},{44,12,11},{45,12,11},{4,13,14},{7,13,14},{9,13,14},{10,13,14},
| |
| 365 | {11,13,14},{21,13,11},{22,13,11},{29,13,11},{34,13,11},{39,13,11},{40,13,11},{46,13,11},{47,13,11},{4,14,14},
| |
| 366 | {5,14,14},{6,14,14},{7,14,14},{29,14,11},{34,14,11},{40,14,11},{48,14,11},{10,15,4},{11,15,4},{12,15,4},{13,15,4},
| |
| 367 | {14,15,4},{15,15,4},{40,15,11},{44,15,11},{48,15,11},{9,16,4},{16,16,4},{17,16,4},{18,16,4},{19,16,4},{20,16,4},
| |
| 368 | {21,16,4},{22,16,4},{40,16,11},{45,16,11},{46,16,11},{47,16,11},{6,17,4},{7,17,4},{8,17,4},{23,17,4},{24,17,4},
| |
| 369 | {25,17,4},{26,17,4},{42,17,4},{43,17,4},{44,17,4},{27,18,4},{28,18,4},{29,18,4},{30,18,4},{31,18,4},{32,18,4},
| |
| 370 | {33,18,4},{34,18,4},{35,18,4},{36,18,4},{37,18,4},{38,18,4},{39,18,4},{40,18,4},{41,18,4}}
| |
| 371 | ||
| 372 | or | |
| 373 | ||
| 374 | {{2,2,4},{3,2,4},{4,2,4},{5,2,4},{6,2,4},{7,2,4},{9,3,14},{10,3,14},{11,3,14},{4,4,14},{5,4,14},{6,4,14},{8,4,14},
| |
| 375 | {9,4,14},{12,4,14},{3,5,14},{4,5,14},{7,5,14},{9,5,14},{10,5,14},{11,5,14},{12,5,14},{13,5,14},{4,6,14},{5,6,14},
| |
| 376 | {6,6,14},{7,6,14},{8,6,14},{10,6,14},{13,6,14},{15,6,4},{24,6,4},{25,6,4},{5,7,14},{8,7,14},{10,7,14},{11,7,14},
| |
| 377 | {12,7,14},{16,7,4},{23,7,4},{5,8,14},{6,8,14},{7,8,14},{17,8,4},{18,8,4},{19,8,4},{20,8,4},{21,8,4},{22,8,4},{3,9,11},
| |
| 378 | {4,9,11},{5,10,11},{6,10,11},{7,10,11},{5,11,11},{8,11,11},{9,11,11},{14,11,11},{5,12,11},{14,12,11},{5,13,11},
| |
| 379 | {8,13,11},{9,13,11},{12,13,11},{13,13,11},{14,13,11},{15,13,11},{16,13,11},{22,13,11},{23,13,11},{4,14,11},{7,14,11},
| |
| 380 | {10,14,11},{14,14,11},{19,14,11},{21,14,11},{4,15,11},{7,15,11},{8,15,11},{9,15,11},{10,15,11},{13,15,11},{16,15,11},
| |
| 381 | {17,15,11},{22,15,11},{23,15,11},{4,16,11},{7,16,11},{13,16,11},{15,16,11},{19,16,11},{24,16,11},{8,17,11},{9,17,11},
| |
| 382 | {12,17,11},{15,17,11},{19,17,11},{21,17,11},{22,17,11},{23,17,11},{2,18,4},{3,18,4},{4,18,4},{25,18,4},{5,19,4},
| |
| 383 | {6,19,4},{7,19,4},{8,19,4},{9,19,4},{10,19,4},{11,19,4},{12,19,4},{13,19,4},{14,19,4},{15,19,4},{16,19,4},{17,19,4},
| |
| 384 | {18,19,4},{19,19,4},{20,19,4},{21,19,4},{22,19,4},{23,19,4},{24,19,4}}
| |
| 385 | ||
| 386 | term.setBackgroundColor(colours.black) | |
| 387 | term.clear() | |
| 388 | ||
| 389 | writeAt(version,(pocket and -2) or 36-#version,depth) | |
| 390 | ||
| 391 | term.setBackgroundColor(term.isColor() and colours.yellow or colours.white) | |
| 392 | term.setTextColor(term.isColor() and colours.lightGrey or colours.black) | |
| 393 | ||
| 394 | if xSize > 48 then | |
| 395 | term.setCursorPos(screenx-15,screeny) | |
| 396 | term.write(string.rep("L",53))
| |
| 397 | term.setCursorPos(screenx-15,screeny+20) | |
| 398 | term.write(string.rep("L",53))
| |
| 399 | ||
| 400 | for i=1,depth do | |
| 401 | term.setCursorPos(screenx-15,screeny+i) | |
| 402 | term.write("L")
| |
| 403 | term.setCursorPos(screenx+37,screeny+i) | |
| 404 | term.write("L")
| |
| 405 | end | |
| 406 | end | |
| 407 | ||
| 408 | while #introBlock > 0 do | |
| 409 | for i=1,5 do if #introBlock > 0 then | |
| 410 | temp = math.random(#introBlock) | |
| 411 | if term.isColor() then term.setBackgroundColor(math.pow(2,introBlock[temp][3])) end | |
| 412 | term.setCursorPos((xSize > 26 and screenx-15 or 0)+introBlock[temp][1],screeny+introBlock[temp][2]) | |
| 413 | term.write("L")
| |
| 414 | table.remove(introBlock,temp) | |
| 415 | end end | |
| 416 | ||
| 417 | temp = os.startTimer(0.05) | |
| 418 | ||
| 419 | while true do | |
| 420 | myEvent = {os.pullEvent()}
| |
| 421 | ||
| 422 | if myEvent[1] == "timer" and myEvent[2] == temp then | |
| 423 | break | |
| 424 | elseif myEvent[1] ~= "timer" and myEvent[1] ~= "key_up" and myEvent[1] ~= "mouse_up" then | |
| 425 | return | |
| 426 | end | |
| 427 | end | |
| 428 | end | |
| 429 | ||
| 430 | temp = os.startTimer(2) | |
| 431 | os.pullEvent() | |
| 432 | end | |
| 433 | ||
| 434 | --------------------------------------------- | |
| 435 | ------------ Help Pages ------------ | |
| 436 | --------------------------------------------- | |
| 437 | ||
| 438 | -- Draw the frame for the help screen. | |
| 439 | local function prepareHelp() | |
| 440 | term.setBackgroundColor(colours.black) | |
| 441 | term.clear() | |
| 442 | ||
| 443 | writeAt("^",35,2)
| |
| 444 | writeAt("|",35,3)
| |
| 445 | writeAt("X",35,10)
| |
| 446 | writeAt("|",35,17)
| |
| 447 | writeAt("v",35,18)
| |
| 448 | ||
| 449 | term.setBackgroundColor(term.isColor() and colours.yellow or colours.white) | |
| 450 | term.setTextColor(term.isColor() and colours.lightGrey or colours.black) | |
| 451 | ||
| 452 | term.setCursorPos(screenx-15,screeny) | |
| 453 | term.write(string.rep("L",53))
| |
| 454 | term.setCursorPos(screenx-15,screeny+depth+1) | |
| 455 | term.write(string.rep("L",53))
| |
| 456 | ||
| 457 | for i=1,depth do | |
| 458 | term.setCursorPos(screenx-15,screeny+i) | |
| 459 | term.write("L")
| |
| 460 | term.setCursorPos(screenx+37,screeny+i) | |
| 461 | term.write("L")
| |
| 462 | end | |
| 463 | end | |
| 464 | ||
| 465 | -- Write a given page of the manual. | |
| 466 | local function writeHelp(page) | |
| 467 | local manual | |
| 468 | ||
| 469 | if page == 1 then | |
| 470 | manual = | |
| 471 | {"BBTetris ("..version..")",
| |
| 472 | string.rep("-",11+#version),
| |
| 473 | "", | |
| 474 | "By Jeffrey Alexander, aka Bomb Bloke.", | |
| 475 | "", | |
| 476 | "Yet another Tetris clone, this one for", | |
| 477 | "ComputerCraft.", | |
| 478 | "", | |
| 479 | "Playable via mouse when used with a touch-", | |
| 480 | "capable display. If using an external", | |
| 481 | "monitor, at least 3x2 blocks is required,", | |
| 482 | "while 5x3 is recommended."} | |
| 483 | elseif page == 2 then | |
| 484 | manual = | |
| 485 | {"Basic Controls",
| |
| 486 | "--------------", | |
| 487 | "", | |
| 488 | "Use your arrow keys (or WSAD) for most", | |
| 489 | "actions.", | |
| 490 | "", | |
| 491 | "On the main menu, left alters your level,", | |
| 492 | "whilst right alters your speed. Use up/down", | |
| 493 | "to change your game mode and space to start.", | |
| 494 | "", | |
| 495 | "Mouse-users may instead click the speed /", | |
| 496 | "level / game mode toggles to change them,", | |
| 497 | "then click the play area to begin."} | |
| 498 | elseif page == 3 then | |
| 499 | manual = | |
| 500 | {"Playing",
| |
| 501 | "-------", | |
| 502 | "", | |
| 503 | "Blocks fall according to the current speed,", | |
| 504 | "which increases every 10k points. You win", | |
| 505 | "if you somehow manage to reach 100k.", | |
| 506 | "", | |
| 507 | "Use the down arrow to drop the block", | |
| 508 | "quickly, or the up arrow to rotate it.", | |
| 509 | "", | |
| 510 | "Space / enter can be used to rotate in the", | |
| 511 | "opposite direction.", | |
| 512 | "", | |
| 513 | "100 points for a line, 300 for two, 700 for", | |
| 514 | "three and 1500 for a Tetris (four lines)!"} | |
| 515 | elseif page == 4 then | |
| 516 | manual = | |
| 517 | {"Playing (Mouse)",
| |
| 518 | "---------------", | |
| 519 | "", | |
| 520 | "Clicking the left side of the grid moves the", | |
| 521 | "block to the left, and clicking the right", | |
| 522 | "functions in a similar manner.", | |
| 523 | "", | |
| 524 | "Click the bottom of the grid to move the", | |
| 525 | "block down quickly, or on the block itself", | |
| 526 | "to rotate. You may click outside the main", | |
| 527 | "play area to rotate the other way.", | |
| 528 | "", | |
| 529 | "The scroll-wheel can also be used to rotate", | |
| 530 | "or move downwards quickly."} | |
| 531 | elseif page == 5 then | |
| 532 | manual = | |
| 533 | {"Alternate Modes",
| |
| 534 | "---------------", | |
| 535 | "", | |
| 536 | "There are three optional game modes", | |
| 537 | "available, which can be combined together to", | |
| 538 | "make your game easier/harder as is your", | |
| 539 | "whim.", | |
| 540 | "", | |
| 541 | "Advanced mode increases the block pool to", | |
| 542 | "nearly double, making for a more complex", | |
| 543 | "game. Tricks come in the form of one of", | |
| 544 | "three rare blocks, each of which has a", | |
| 545 | "unique power. Quota mode tasks you to clear", | |
| 546 | "pre-filled grids in order to advance levels."} | |
| 547 | end | |
| 548 | ||
| 549 | for i=1,depth-2 do | |
| 550 | if manual[i] then | |
| 551 | writeAt(manual[i]..string.rep(" ",44-#manual[i]),-13,i+1)
| |
| 552 | else | |
| 553 | writeAt(string.rep(" ",44),-13,i+1)
| |
| 554 | end | |
| 555 | end | |
| 556 | end | |
| 557 | ||
| 558 | -- Explain stuff. | |
| 559 | local function help() | |
| 560 | local page = 1 | |
| 561 | prepareHelp() | |
| 562 | writeHelp(page) | |
| 563 | ||
| 564 | while true do | |
| 565 | myEvent = {os.pullEvent()}
| |
| 566 | ||
| 567 | if clickedAt(35,10) or pressedKey(keys.h,keys.x,keys.q) then | |
| 568 | return | |
| 569 | elseif myEvent[1] == "monitor_resize" and mon then | |
| 570 | if myEvent[2] == mon.side then | |
| 571 | enforceScreenSize() | |
| 572 | prepareHelp() | |
| 573 | writeHelp(page) | |
| 574 | end | |
| 575 | elseif clickedAt(35,1,4) or pressedKey(keys.w,keys.up) or (myEvent[1] == "mouse_scroll" and myEvent[2] == -1) then | |
| 576 | page = (page==1) and 5 or (page-1) | |
| 577 | writeHelp(page) | |
| 578 | elseif clickedAt(35,16,19) or pressedKey(keys.s,keys.down) or (myEvent[1] == "mouse_scroll" and myEvent[2] == 1) then | |
| 579 | page = (page==5) and 1 or (page+1) | |
| 580 | writeHelp(page) | |
| 581 | elseif myEvent[1] == "terminate" then | |
| 582 | exitGame() | |
| 583 | elseif myEvent[1] == "musicFinished" then | |
| 584 | os.queueEvent("musicPlay",musicFile)
| |
| 585 | end | |
| 586 | end | |
| 587 | end | |
| 588 | ||
| 589 | --------------------------------------------- | |
| 590 | ------------ Main Menu ------------ | |
| 591 | --------------------------------------------- | |
| 592 | ||
| 593 | local function menu() | |
| 594 | running = true | |
| 595 | drawNumeral() | |
| 596 | writeAt((level>9 and "" or " ")..tostring(level),17,15) | |
| 597 | writeAt(tostring(speed),18,18) | |
| 598 | ||
| 599 | while running do | |
| 600 | myEvent = {os.pullEvent()}
| |
| 601 | ||
| 602 | if pressedKey(keys.left,keys.a) or clickedAt(13,19,13,16) then | |
| 603 | level = (level == 12) and 0 or (level+1) | |
| 604 | writeAt((level>9 and "" or " ")..tostring(level),17,15) | |
| 605 | elseif pressedKey(keys.right,keys.d) or clickedAt(13,19,16,19) then | |
| 606 | speed = (speed == 9) and 0 or (speed+1) | |
| 607 | writeAt(tostring(speed),18,18) | |
| 608 | elseif pressedKey(keys.space,keys.enter) or clickedAt(1,12,0,20) then | |
| 609 | running = false | |
| 610 | elseif ((touchedMe() and myEvent[3] < screenx and myEvent[4] == screeny + 2) or pressedKey(keys.h)) and not pocket then | |
| 611 | help() | |
| 612 | drawBorder() | |
| 613 | drawNumeral() | |
| 614 | writeAt((level>9 and "" or " ")..tostring(level),17,15) | |
| 615 | writeAt(tostring(speed),18,18) | |
| 616 | elseif pressedKey(keys.up,keys.w) or (myEvent[1] == "mouse_scroll" and myEvent[2] == -1) then | |
| 617 | gamemode = (gamemode == 1) and 8 or (gamemode-1) | |
| 618 | drawNumeral() | |
| 619 | elseif pressedKey(keys.down,keys.s) or (myEvent[1] == "mouse_scroll" and myEvent[2] == 1) then | |
| 620 | gamemode = (gamemode == 8) and 1 or (gamemode+1) | |
| 621 | drawNumeral() | |
| 622 | elseif pressedKey(keys.x,keys.q) then | |
| 623 | os.pullEvent("char")
| |
| 624 | exitGame() | |
| 625 | elseif myEvent[1] == "terminate" then | |
| 626 | exitGame() | |
| 627 | elseif touchedMe() and myEvent[3] > screenx+21 then | |
| 628 | term.setTextColor(term.isColor() and colours.red or colours.white) | |
| 629 | term.setCursorPos(myEvent[3],myEvent[4]) | |
| 630 | for i=0,2 do if myEvent[4] == screeny + 14 + i * 2 then | |
| 631 | gamemode = gamemode + (bit.band(gamemode-1,bit.blshift(1,i))==bit.blshift(1,i) and (-bit.blshift(1,i)) or bit.blshift(1,i)) | |
| 632 | drawNumeral() | |
| 633 | break | |
| 634 | end end | |
| 635 | if myEvent[4] == screeny + 2 then exitGame() end | |
| 636 | elseif myEvent[1] == "monitor_resize" and mon then | |
| 637 | if myEvent[2] == mon.side then | |
| 638 | enforceScreenSize() | |
| 639 | drawBorder() | |
| 640 | drawNumeral() | |
| 641 | writeAt((level>9 and "" or " ")..tostring(level),17,15) | |
| 642 | writeAt(tostring(speed),18,18) | |
| 643 | end | |
| 644 | elseif myEvent[1] == "peripheral_detach" and mon then | |
| 645 | if myEvent[2] == mon.side then exitGame("I've lost my monitor - your turtle didn't mine it, I hope?") end
| |
| 646 | end | |
| 647 | end | |
| 648 | end | |
| 649 | ||
| 650 | --------------------------------------------- | |
| 651 | ------------Primary Game Function------------ | |
| 652 | --------------------------------------------- | |
| 653 | ||
| 654 | local function game() | |
| 655 | local falling, knocked, score, curBlock, nextSpeed, startSpeed, startLevel, loaded, rotation = true, false, 0, 1, 9999, speed, level, false, 0 | |
| 656 | local nextBlock = math.random(bit.band(gamemode,1)==1 and 7 or 13) | |
| 657 | local x, y, blockTimer, lines, held, flicker, flickerTimer | |
| 658 | ||
| 659 | os.queueEvent("musicPlay",musicFile)
| |
| 660 | os.queueEvent(playMusic and "musicResume" or "musicPause") | |
| 661 | ||
| 662 | for i=1,depth do grid[i] = {} end
| |
| 663 | ||
| 664 | -- Resume an old game? | |
| 665 | if saves[gamemode] then | |
| 666 | writeAt(" Load old ",2,9)
| |
| 667 | writeAt(" game ",2,10)
| |
| 668 | writeAt("[Y]es [N]o",2,11)
| |
| 669 | ||
| 670 | while true do | |
| 671 | myEvent = {os.pullEvent()}
| |
| 672 | ||
| 673 | if pressedKey(keys.y) or clickedAt(3,11) then | |
| 674 | running = true | |
| 675 | break | |
| 676 | elseif pressedKey(keys.n) or clickedAt(9,11) then | |
| 677 | running = false | |
| 678 | break | |
| 679 | elseif myEvent[1] == "monitor_resize" and mon then | |
| 680 | if myEvent[2] == mon.side then | |
| 681 | enforceScreenSize() | |
| 682 | redrawGame(score) | |
| 683 | ||
| 684 | writeAt(" Load old ",2,9)
| |
| 685 | writeAt(" game ",2,10)
| |
| 686 | writeAt("[Y]es [N]o",2,11)
| |
| 687 | end | |
| 688 | elseif myEvent[1] == "peripheral_detach" and mon then | |
| 689 | if myEvent[2] == mon.side then exitGame("I've lost my monitor - your turtle didn't mine it, I hope?") end
| |
| 690 | elseif myEvent[1] == "terminate" then | |
| 691 | exitGame() | |
| 692 | end | |
| 693 | end | |
| 694 | ||
| 695 | if running then | |
| 696 | x = saves[gamemode]["x"] | |
| 697 | y = saves[gamemode]["y"] | |
| 698 | rotation = saves[gamemode]["rotation"] | |
| 699 | curBlock = saves[gamemode]["curBlock"] | |
| 700 | nextBlock = saves[gamemode]["nextBlock"] | |
| 701 | score = saves[gamemode]["score"] | |
| 702 | speed = saves[gamemode]["speed"] | |
| 703 | nextSpeed = saves[gamemode]["nextSpeed"] | |
| 704 | startSpeed = saves[gamemode]["startSpeed"] | |
| 705 | level = saves[gamemode]["level"] | |
| 706 | startLevel = saves[gamemode]["startLevel"] | |
| 707 | grid = saves[gamemode]["grid"] | |
| 708 | saves[gamemode] = nil | |
| 709 | loaded = true | |
| 710 | end | |
| 711 | end | |
| 712 | ||
| 713 | running = true | |
| 714 | ||
| 715 | -- Clear off the menu. | |
| 716 | term.setBackgroundColor(colours.black) | |
| 717 | for i=1,7 do | |
| 718 | term.setCursorPos(screenx+2,screeny+i+6) | |
| 719 | term.write(string.rep(" ",10))
| |
| 720 | end | |
| 721 | ||
| 722 | if loaded then | |
| 723 | term.setTextColor(term.isColor() and colours.lightGrey or colours.black) | |
| 724 | for yy=1,depth do | |
| 725 | term.setCursorPos(screenx+2,screeny+yy) | |
| 726 | for xx=1,10 do if grid[depth+1-yy][xx] ~= nil then | |
| 727 | term.setBackgroundColor(term.isColor() and bit.blshift(1,grid[depth+1-yy][xx]) or colours.white) | |
| 728 | term.write("L")
| |
| 729 | else | |
| 730 | term.setBackgroundColor(colours.black) | |
| 731 | term.write(" ")
| |
| 732 | end end | |
| 733 | end | |
| 734 | else fillGrid() end | |
| 735 | ||
| 736 | writeAt("[P]ause",pocket and 21 or 22,4)
| |
| 737 | if note then writeAt("[M]usic",22,6) end
| |
| 738 | writeAt("Next",14,1)
| |
| 739 | writeAt("Score",14,8)
| |
| 740 | writeAt(string.rep(" ",6-#tostring(score))..tostring(score),13,9)
| |
| 741 | writeAt((level>9 and "" or " ")..tostring(level),17,15) | |
| 742 | writeAt(tostring(speed),18,18) | |
| 743 | ||
| 744 | -- Primary game loop. | |
| 745 | while running do | |
| 746 | if rotation < 4 then -- The last type of block "may" persist after line checks. | |
| 747 | if loaded then | |
| 748 | loaded = false | |
| 749 | else | |
| 750 | curBlock = nextBlock | |
| 751 | ||
| 752 | -- Change the "next block" display. | |
| 753 | drawBlock(nextBlock,0,(#block[nextBlock][1] < 3 and 15 or 14),(#block[nextBlock] < 3 and 3 or 2), false, false) | |
| 754 | nextBlock = math.random(bit.band(gamemode,1)==1 and 7 or 13) | |
| 755 | ||
| 756 | -- Trick block will be next! | |
| 757 | if bit.band(gamemode-1,2)==2 and math.random(20) == 20 then nextBlock = 13 + math.random(3) end | |
| 758 | ||
| 759 | -- Prepare a new falling block. | |
| 760 | x, y, rotation = (#block[curBlock][1] < 4 and 5 or 4), 1, 0 | |
| 761 | end | |
| 762 | ||
| 763 | drawBlock(nextBlock,0,(#block[nextBlock][1] < 3 and 15 or 14),(#block[nextBlock] < 3 and 3 or 2), true, nextBlock>13) | |
| 764 | drawBlock(curBlock,rotation,x,y,true,false) | |
| 765 | ||
| 766 | -- Can play continue? | |
| 767 | if checkBlock(curBlock,rotation,x,y) then | |
| 768 | falling, knocked, flicker, blockTimer, flickerTimer = true, false, false, os.startTimer((10-speed)/10), os.startTimer(0.3) | |
| 769 | else running = false end | |
| 770 | else | |
| 771 | falling, rotation, flickerTimer = true, 0, os.startTimer(0) | |
| 772 | drawBlock(curBlock,rotation,x,y,true,flicker) | |
| 773 | end | |
| 774 | ||
| 775 | -- Stuff that happens while a block falls. | |
| 776 | while falling do | |
| 777 | myEvent = {os.pullEvent()}
| |
| 778 | ||
| 779 | -- Is the user still holding down "down" after the last block fell? | |
| 780 | if held then | |
| 781 | if not ((myEvent[1] == "timer" and myEvent[2] ~= blockTimer) | |
| 782 | or pressedKey(keys.down,keys.s) or myEvent[1] == "char") | |
| 783 | then held = false end | |
| 784 | end | |
| 785 | ||
| 786 | -- Trick blocks flash. | |
| 787 | if myEvent[1] == "timer" and myEvent[2] == flickerTimer and curBlock > 13 then | |
| 788 | flicker = not flicker | |
| 789 | flickerTimer = os.startTimer(0.3) | |
| 790 | drawBlock(curBlock,rotation,x,y,true,flicker) | |
| 791 | ||
| 792 | elseif curBlock > 14 and (clickedAt(x,x+1+(bit.band(rotation,1)==1 and #block[curBlock] or #block[curBlock][1]),y-1,y+(bit.band(rotation,1)==1 and #block[curBlock][1] or #block[curBlock])) or pressedKey(keys.up,keys.w,keys.space,keys.enter)) then | |
| 793 | ||
| 794 | -- Erasure! | |
| 795 | if curBlock == 15 then | |
| 796 | for i=depth-1-y,1,-1 do if grid[i][x] ~= nil then | |
| 797 | term.setCursorPos(screenx+1+x,screeny+depth+1-i) | |
| 798 | term.setBackgroundColor(colours.black) | |
| 799 | term.write(" ")
| |
| 800 | grid[i][x] = nil | |
| 801 | break | |
| 802 | end end | |
| 803 | ||
| 804 | if bit.band(gamemode-1,4)==4 then | |
| 805 | -- Possible to fulfil the quota here without creating a line. | |
| 806 | lines = 0 | |
| 807 | for yy=1,depth do for xx=1,10 do if grid[xx][yy] == 14 then | |
| 808 | yy=depth | |
| 809 | xx=10 | |
| 810 | lines = 1 | |
| 811 | end end end | |
| 812 | ||
| 813 | if lines ~= 1 then | |
| 814 | score = score + 10000 | |
| 815 | level = level + 1 | |
| 816 | rotation = 0 | |
| 817 | falling = false | |
| 818 | gameover() | |
| 819 | fillGrid() | |
| 820 | ||
| 821 | writeAt(string.rep(" ",6-#tostring(score))..tostring(score),13,9)
| |
| 822 | ||
| 823 | if score > 99999 then running = false end | |
| 824 | ||
| 825 | -- Check for a score record. | |
| 826 | if score > highScore[gamemode] then | |
| 827 | highScore[gamemode] = score | |
| 828 | writeAt(string.rep(" ",6-#tostring(highScore[gamemode]))..tostring(highScore[gamemode]),13,12)
| |
| 829 | end | |
| 830 | ||
| 831 | writeAt((level>9 and "" or " ")..tostring(level),17,15) | |
| 832 | ||
| 833 | -- Increment speed. | |
| 834 | nextSpeed = nextSpeed + 10000 | |
| 835 | speed = (speed==9) and 9 or (speed+1) | |
| 836 | writeAt(tostring(speed),18,18) | |
| 837 | end | |
| 838 | end | |
| 839 | ||
| 840 | -- Fill! | |
| 841 | elseif curBlock == 16 and grid[depth-2-y][x] == nil then | |
| 842 | rotation = 1 | |
| 843 | for i=1,depth-3-y do if grid[i][x] ~= nil then rotation = i+1 end end | |
| 844 | term.setCursorPos(screenx+1+x,screeny+depth+1-rotation) | |
| 845 | term.setBackgroundColor(colours.white) | |
| 846 | term.setTextColor(term.isColor() and colours.lightGrey or colours.black) | |
| 847 | term.write("L")
| |
| 848 | grid[rotation][x] = 32 | |
| 849 | falling, rotation = false, 20 + rotation -- Rotation used here as a flag to indicate we're still actually falling. | |
| 850 | end | |
| 851 | ||
| 852 | -- Block rotation. | |
| 853 | elseif (clickedAt(x,x+1+(bit.band(rotation,1)==1 and #block[curBlock] or #block[curBlock][1]),y-1,y+(bit.band(rotation,1)==1 and #block[curBlock][1] or #block[curBlock])) or pressedKey(keys.up,keys.w) or (myEvent[1] == "mouse_scroll" and myEvent[2] == -1)) and checkBlock(curBlock,rotation==3 and 0 or (rotation+1),x,y) then | |
| 854 | drawBlock(curBlock,rotation,x,y,false,flicker) | |
| 855 | rotation = (rotation==3) and 0 or (rotation+1) | |
| 856 | drawBlock(curBlock,rotation,x,y,true,flicker) | |
| 857 | ||
| 858 | elseif (myEvent[1] == "timer" and myEvent[2] == blockTimer) or clickedAt(1,12,depth-2,depth+1) or (pressedKey(keys.down,keys.s) and not held) or (myEvent[1] == "mouse_scroll" and myEvent[2] == 1) then | |
| 859 | ||
| 860 | -- Move the block down if we can. | |
| 861 | if checkBlock(curBlock,rotation,x,y+1) then | |
| 862 | drawBlock(curBlock,rotation,x,y,false,flicker) | |
| 863 | y = y + 1 | |
| 864 | drawBlock(curBlock,rotation,x,y,true,flicker) | |
| 865 | knocked = false | |
| 866 | ||
| 867 | -- Brick's stopped moving down, add it to the grid. | |
| 868 | elseif knocked then | |
| 869 | if curBlock < 15 then | |
| 870 | for yy=1,#block[curBlock] do for xx=1,#block[curBlock][1] do if block[curBlock][yy][xx] == 1 then | |
| 871 | if rotation == 0 then | |
| 872 | grid[depth+2-y-yy][x+xx-1] = (curBlock == 14 and 15 or curBlock) | |
| 873 | elseif rotation == 1 then | |
| 874 | grid[depth+2-y-xx][x+#block[curBlock]-yy] = (curBlock == 14 and 15 or curBlock) | |
| 875 | elseif rotation == 2 then | |
| 876 | grid[depth+1-y-#block[curBlock]+yy][x+#block[curBlock][1]-xx] = (curBlock == 14 and 15 or curBlock) | |
| 877 | elseif rotation == 3 then | |
| 878 | grid[depth+1-y-#block[curBlock][1]+xx][x+yy-1] = (curBlock == 14 and 15 or curBlock) | |
| 879 | end | |
| 880 | end end end | |
| 881 | end | |
| 882 | ||
| 883 | if curBlock > 13 then drawBlock(curBlock,rotation,x,y,curBlock==14,false) end | |
| 884 | falling = false | |
| 885 | held = true -- This is used to stop the NEXT block being pelted downwards if you were holding a "down" button. | |
| 886 | ||
| 887 | -- Brick has "knocked" other bricks, but hasn't yet locked in place. | |
| 888 | else knocked = true end | |
| 889 | ||
| 890 | if falling then blockTimer = os.startTimer((10-speed)/10) end | |
| 891 | ||
| 892 | -- Pause the game. | |
| 893 | elseif (myEvent[1] == "monitor_resize" and mon) or pressedKey(keys.p) or (touchedMe() and myEvent[3] > screenx+21 and myEvent[4] == screeny+4) then | |
| 894 | -- Something altered my monitor! | |
| 895 | if myEvent[1] == "monitor_resize" and mon then | |
| 896 | if myEvent[2] == mon.side then | |
| 897 | enforceScreenSize() | |
| 898 | redrawGame(score) | |
| 899 | drawBlock(curBlock,rotation,x,y,true,flicker) | |
| 900 | drawBlock(nextBlock,0,(#block[nextBlock][1] < 3 and 15 or 14),(#block[nextBlock] < 3 and 3 or 2), true, nextBlock>13) | |
| 901 | end | |
| 902 | end | |
| 903 | ||
| 904 | writeAt(" PAUSED ",2,10)
| |
| 905 | blockTimer = os.startTimer(1) | |
| 906 | ||
| 907 | while true do | |
| 908 | myEvent = {os.pullEvent()}
| |
| 909 | ||
| 910 | if myEvent[1] == "key" or touchedMe() then | |
| 911 | break | |
| 912 | elseif myEvent[1] == "monitor_resize" and mon then | |
| 913 | if myEvent[2] == mon.side then | |
| 914 | enforceScreenSize() | |
| 915 | redrawGame(score) | |
| 916 | drawBlock(curBlock,rotation,x,y,true,flicker) | |
| 917 | drawBlock(nextBlock,0,(#block[nextBlock][1] < 3 and 15 or 14),(#block[nextBlock] < 3 and 3 or 2), true, nextBlock>13) | |
| 918 | ||
| 919 | falling = not falling | |
| 920 | writeAt(falling and " PAUSED " or string.rep(" ",10),2,10)
| |
| 921 | blockTimer = os.startTimer(1) | |
| 922 | end | |
| 923 | elseif myEvent[1] == "timer" and myEvent[2] == blockTimer then | |
| 924 | falling = not falling | |
| 925 | writeAt(falling and " PAUSED " or string.rep(" ",10),2,10)
| |
| 926 | blockTimer = os.startTimer(1) | |
| 927 | elseif myEvent[1] == "peripheral_detach" and mon then | |
| 928 | if myEvent[2] == mon.side then exitGame("I've lost my monitor - your turtle didn't mine it, I hope?") end
| |
| 929 | elseif myEvent[1] == "terminate" then | |
| 930 | exitGame() | |
| 931 | elseif myEvent[1] == "musicFinished" then | |
| 932 | os.queueEvent("musicPlay",musicFile)
| |
| 933 | end | |
| 934 | end | |
| 935 | ||
| 936 | term.setTextColor(term.isColor() and colours.lightGrey or colours.black) | |
| 937 | term.setCursorPos(screenx+2,screeny+10) | |
| 938 | for xx=1,10 do if grid[10][xx] ~= nil then | |
| 939 | term.setBackgroundColor(term.isColor() and bit.blshift(1,grid[10][xx]) or colours.white) | |
| 940 | term.write("L")
| |
| 941 | else | |
| 942 | term.setBackgroundColor(colours.black) | |
| 943 | term.write(" ")
| |
| 944 | end end | |
| 945 | drawBlock(curBlock,rotation,x,y,true,flicker) | |
| 946 | blockTimer, flickerTimer, falling = os.startTimer((10-speed)/10), os.startTimer(0.3), true | |
| 947 | ||
| 948 | -- Toggle music playback. | |
| 949 | elseif pressedKey(keys.m) or (touchedMe() and myEvent[3] > screenx+21 and myEvent[4] == screeny+6) then | |
| 950 | playMusic = not playMusic | |
| 951 | os.queueEvent(playMusic and "musicResume" or "musicPause") | |
| 952 | ||
| 953 | -- Repeat music. | |
| 954 | elseif myEvent[1] == "musicFinished" then | |
| 955 | os.queueEvent("musicPlay",musicFile)
| |
| 956 | ||
| 957 | -- Display the help screen. | |
| 958 | elseif ((touchedMe() and myEvent[3] < screenx and myEvent[4] == screeny + 2) or pressedKey(keys.h)) and not pocket then | |
| 959 | help() | |
| 960 | redrawGame(score) | |
| 961 | drawBlock(curBlock,rotation,x,y,true,flicker) | |
| 962 | drawBlock(nextBlock,0,(#block[nextBlock][1] < 3 and 15 or 14),(#block[nextBlock] < 3 and 3 or 2), true, nextBlock>13) | |
| 963 | blockTimer, flickerTimer = os.startTimer((10-speed)/10), os.startTimer(0.3) | |
| 964 | ||
| 965 | -- User is attempting to end game. | |
| 966 | elseif pressedKey(keys.x,keys.q) or (touchedMe() and myEvent[3] > screenx+21 and myEvent[4] == screeny+2) then | |
| 967 | if canSave then | |
| 968 | writeAt(" Save the ",2,9)
| |
| 969 | writeAt(" game ",2,10)
| |
| 970 | writeAt("[Y]es [N]o",2,11)
| |
| 971 | ||
| 972 | while true do | |
| 973 | myEvent = {os.pullEvent()}
| |
| 974 | ||
| 975 | if pressedKey(keys.y) or clickedAt(3,11) then | |
| 976 | running = true | |
| 977 | break | |
| 978 | elseif pressedKey(keys.n) or clickedAt(9,11) then | |
| 979 | running = false | |
| 980 | break | |
| 981 | elseif myEvent[1] == "monitor_resize" and mon then | |
| 982 | if myEvent[2] == mon.side then | |
| 983 | enforceScreenSize() | |
| 984 | redrawGame(score) | |
| 985 | drawBlock(curBlock,rotation,x,y,true,flicker) | |
| 986 | drawBlock(nextBlock,0,(#block[nextBlock][1] < 3 and 15 or 14),(#block[nextBlock] < 3 and 3 or 2), true, nextBlock>13) | |
| 987 | ||
| 988 | writeAt(" Save the ",2,9)
| |
| 989 | writeAt(" game ",2,10)
| |
| 990 | writeAt("[Y]es [N]o",2,11)
| |
| 991 | end | |
| 992 | elseif myEvent[1] == "peripheral_detach" and mon then | |
| 993 | if myEvent[2] == mon.side then exitGame("I've lost my monitor - your turtle didn't mine it, I hope?") end
| |
| 994 | elseif myEvent[1] == "terminate" then | |
| 995 | exitGame() | |
| 996 | end | |
| 997 | end | |
| 998 | else running = false end | |
| 999 | ||
| 1000 | -- User wants to save current progress. | |
| 1001 | if running then | |
| 1002 | saves[gamemode] = {}
| |
| 1003 | saves[gamemode]["x"] = x | |
| 1004 | saves[gamemode]["y"] = y | |
| 1005 | saves[gamemode]["rotation"] = rotation | |
| 1006 | saves[gamemode]["curBlock"] = curBlock | |
| 1007 | saves[gamemode]["nextBlock"] = nextBlock | |
| 1008 | saves[gamemode]["score"] = score | |
| 1009 | saves[gamemode]["speed"] = speed | |
| 1010 | saves[gamemode]["nextSpeed"] = nextSpeed | |
| 1011 | saves[gamemode]["startSpeed"] = startSpeed | |
| 1012 | saves[gamemode]["level"] = level | |
| 1013 | saves[gamemode]["startLevel"] = startLevel | |
| 1014 | saves[gamemode]["grid"] = {}
| |
| 1015 | for yy=1,depth do | |
| 1016 | saves[gamemode]["grid"][yy] = {}
| |
| 1017 | for a,b in pairs(grid[yy]) do saves[gamemode]["grid"][yy][a] = b end | |
| 1018 | end | |
| 1019 | end | |
| 1020 | ||
| 1021 | falling, running, rotation = false, false, 10 -- Rotation used here as a flag to bypass the "game over" animation. | |
| 1022 | ||
| 1023 | -- User is trying to out-right quit the game. | |
| 1024 | elseif myEvent[1] == "terminate" then | |
| 1025 | exitGame() | |
| 1026 | ||
| 1027 | -- Move block left. | |
| 1028 | elseif (clickedAt(1,7,0,depth-1) or pressedKey(keys.left,keys.a)) and checkBlock(curBlock,rotation,x-1,y) then | |
| 1029 | drawBlock(curBlock,rotation,x,y,false,flicker) | |
| 1030 | x = x - 1 | |
| 1031 | drawBlock(curBlock,rotation,x,y,true,flicker) | |
| 1032 | ||
| 1033 | -- Move block right. | |
| 1034 | elseif (clickedAt(6,12,0,depth-1) or pressedKey(keys.right,keys.d)) and checkBlock(curBlock,rotation,x+1,y) then | |
| 1035 | drawBlock(curBlock,rotation,x,y,false,flicker) | |
| 1036 | x = x + 1 | |
| 1037 | drawBlock(curBlock,rotation,x,y,true,flicker) | |
| 1038 | ||
| 1039 | -- Rotating the other way. | |
| 1040 | elseif ((touchedMe() and (myEvent[3] < screenx+1 or myEvent[3] > screenx+12)) or pressedKey(keys.space,keys.enter)) and checkBlock(curBlock,rotation==0 and 3 or (rotation-1),x,y) and curBlock < 14 then | |
| 1041 | drawBlock(curBlock,rotation,x,y,false,flicker) | |
| 1042 | rotation = (rotation==0) and 3 or (rotation-1) | |
| 1043 | drawBlock(curBlock,rotation,x,y,true,flicker) | |
| 1044 | ||
| 1045 | elseif myEvent[1] == "peripheral_detach" and mon then | |
| 1046 | if myEvent[2] == mon.side then exitGame("I've lost my monitor - your turtle didn't mine it, I hope?") end
| |
| 1047 | end | |
| 1048 | end | |
| 1049 | ||
| 1050 | -- Look for complete lines. | |
| 1051 | if running then | |
| 1052 | lines = {}
| |
| 1053 | for yy=((rotation>3) and (40-rotation) or y),((rotation>3) and (40-rotation) or y+(bit.band(rotation,1)==1 and #block[curBlock][1] or #block[curBlock])-1) do | |
| 1054 | falling = true | |
| 1055 | ||
| 1056 | for xx=1,10 do if yy < depth+1 then | |
| 1057 | if grid[depth+1-yy][xx] == nil then | |
| 1058 | falling = false | |
| 1059 | break | |
| 1060 | end | |
| 1061 | else falling = false end end | |
| 1062 | ||
| 1063 | if falling then | |
| 1064 | lines[#lines+1] = yy | |
| 1065 | table.remove(grid,depth+1-yy) | |
| 1066 | grid[depth] = {}
| |
| 1067 | end | |
| 1068 | end | |
| 1069 | ||
| 1070 | if #lines > 0 then | |
| 1071 | ||
| 1072 | -- Blink the complete lines a few times. | |
| 1073 | falling = true | |
| 1074 | term.setBackgroundColor(term.isColor() and colours.black or colours.white) | |
| 1075 | term.setTextColor(term.isColor() and colours.lightGrey or colours.black) | |
| 1076 | for i=1,6 do | |
| 1077 | if not term.isColor() then term.setBackgroundColor(falling and colours.white or colours.black) end | |
| 1078 | for j=1,#lines do | |
| 1079 | term.setCursorPos(screenx+2,screeny+lines[j]) | |
| 1080 | term.write(string.rep(falling and "L" or " ",10)) | |
| 1081 | end | |
| 1082 | falling = not falling | |
| 1083 | ||
| 1084 | blockTimer = os.startTimer(0.1) | |
| 1085 | while myEvent[2] ~= blockTimer do myEvent = {os.pullEvent("timer")} end
| |
| 1086 | end | |
| 1087 | ||
| 1088 | -- Collapse the on-screen grid. | |
| 1089 | for yy=1,lines[#lines] do | |
| 1090 | term.setCursorPos(screenx+2,screeny+yy) | |
| 1091 | for xx=1,10 do if grid[depth+1-yy][xx] ~= nil then | |
| 1092 | term.setBackgroundColor(term.isColor() and bit.blshift(1,grid[depth+1-yy][xx]) or colours.white) | |
| 1093 | term.write("L")
| |
| 1094 | else | |
| 1095 | term.setBackgroundColor(colours.black) | |
| 1096 | term.write(" ")
| |
| 1097 | end end | |
| 1098 | end | |
| 1099 | ||
| 1100 | if bit.band(gamemode-1,4)==4 then | |
| 1101 | -- Quota reached? | |
| 1102 | for yy=1,depth do for xx=1,10 do if grid[xx][yy] == 14 then | |
| 1103 | yy=depth | |
| 1104 | xx=10 | |
| 1105 | lines = 1 | |
| 1106 | end end end | |
| 1107 | ||
| 1108 | if lines ~= 1 then | |
| 1109 | score = score + 10000 | |
| 1110 | level = level + 1 | |
| 1111 | rotation = 0 | |
| 1112 | falling = false | |
| 1113 | gameover() | |
| 1114 | fillGrid() | |
| 1115 | end | |
| 1116 | else | |
| 1117 | -- Increment score in the usual way. | |
| 1118 | if #lines == 1 then | |
| 1119 | score = score + 100 | |
| 1120 | elseif #lines == 2 then | |
| 1121 | score = score + 300 | |
| 1122 | elseif #lines == 3 then | |
| 1123 | score = score + 700 | |
| 1124 | elseif #lines == 4 then | |
| 1125 | score = score + 1500 | |
| 1126 | end | |
| 1127 | end | |
| 1128 | ||
| 1129 | writeAt(string.rep(" ",6-#tostring(score))..tostring(score),13,9)
| |
| 1130 | ||
| 1131 | if score > 99999 then running = false end | |
| 1132 | ||
| 1133 | -- Check for a score record. | |
| 1134 | if score > highScore[gamemode] then | |
| 1135 | highScore[gamemode] = score | |
| 1136 | writeAt(string.rep(" ",6-#tostring(highScore[gamemode]))..tostring(highScore[gamemode]),13,12)
| |
| 1137 | end | |
| 1138 | ||
| 1139 | writeAt((level>9 and "" or " ")..tostring(level),17,15) | |
| 1140 | ||
| 1141 | -- Increment speed? | |
| 1142 | if score > nextSpeed then | |
| 1143 | nextSpeed = nextSpeed + 10000 | |
| 1144 | speed = (speed==9) and 9 or (speed+1) | |
| 1145 | writeAt(tostring(speed),18,18) | |
| 1146 | end | |
| 1147 | ||
| 1148 | blockTimer = os.startTimer((10-speed)/10) | |
| 1149 | end | |
| 1150 | end | |
| 1151 | end | |
| 1152 | ||
| 1153 | -- Game over. | |
| 1154 | if rotation < 4 then | |
| 1155 | writeAt(score < 100000 and "GAME OVER" or "!!WINNER!!",2,10) | |
| 1156 | ||
| 1157 | -- Assign bonus points. | |
| 1158 | score = score + (100*startSpeed) + startLevel | |
| 1159 | writeAt(string.rep(" ",6-#tostring(score))..tostring(score),13,9)
| |
| 1160 | ||
| 1161 | -- Check for a score record. | |
| 1162 | if score > highScore[gamemode] then | |
| 1163 | highScore[gamemode] = score | |
| 1164 | writeAt(string.rep(" ",6-#tostring(highScore[gamemode]))..tostring(highScore[gamemode]),13,12)
| |
| 1165 | end | |
| 1166 | ||
| 1167 | gameover() | |
| 1168 | end | |
| 1169 | ||
| 1170 | speed = startSpeed | |
| 1171 | level = startLevel | |
| 1172 | end | |
| 1173 | ||
| 1174 | --------------------------------------------- | |
| 1175 | ------------ Init ------------ | |
| 1176 | --------------------------------------------- | |
| 1177 | ||
| 1178 | -- Override the event-puller. | |
| 1179 | OGeventPuller = os.pullEvent | |
| 1180 | os.pullEvent = os.pullEventRaw | |
| 1181 | ||
| 1182 | -- Load the INI file. | |
| 1183 | if fs.exists(shell.resolve(".").."\\bbtetris.ini") then
| |
| 1184 | local readIn, readTable | |
| 1185 | myEvent = fs.open(shell.resolve(".").."\\bbtetris.ini", "r")
| |
| 1186 | readIn = myEvent.readLine() | |
| 1187 | ||
| 1188 | while readIn do | |
| 1189 | readTable = {}
| |
| 1190 | readIn = readIn:gsub("="," "):lower()
| |
| 1191 | for i in readIn:gmatch("%S+") do readTable[#readTable+1] = i end
| |
| 1192 | ||
| 1193 | if readTable[1] == "nointro" and readTable[2] then | |
| 1194 | if readTable[2] == "yes" or readTable[2] == "y" or readTable[2] == "true" or readTable[2] == "on" or readTable[2] == "1" then skipIntro = true end | |
| 1195 | elseif readTable[1] == "nomonitor" and readTable[2] then | |
| 1196 | if readTable[2] == "yes" or readTable[2] == "y" or readTable[2] == "true" or readTable[2] == "on" or readTable[2] == "1" then skipMonitor = true end | |
| 1197 | elseif readTable[1] == "defaultmonitorside" and readTable[2] then | |
| 1198 | defaultMonitor = readTable[2] | |
| 1199 | elseif readTable[1] == "defaultspeed" and tonumber(readTable[2]) then | |
| 1200 | if tonumber(readTable[2]) > -1 and tonumber(readTable[2]) < 10 then speed = tonumber(readTable[2]) end | |
| 1201 | elseif readTable[1] == "defaultlevel" and tonumber(readTable[2]) then | |
| 1202 | if tonumber(readTable[2]) > -1 and tonumber(readTable[2]) < 13 then level = tonumber(readTable[2]) end | |
| 1203 | elseif readTable[1] == "defaultmode" and tonumber(readTable[2]) then | |
| 1204 | if tonumber(readTable[2]) > 0 and tonumber(readTable[2]) < 9 then gamemode = tonumber(readTable[2]) end | |
| 1205 | elseif readTable[1] == "nomusic" and readTable[2] then | |
| 1206 | if readTable[2] == "yes" or readTable[2] == "y" or readTable[2] == "true" or readTable[2] == "on" or readTable[2] == "1" then playMusic = false end | |
| 1207 | end | |
| 1208 | ||
| 1209 | readIn = myEvent.readLine() | |
| 1210 | end | |
| 1211 | ||
| 1212 | myEvent.close() | |
| 1213 | else | |
| 1214 | myEvent = fs.open(shell.resolve(".").."\\bbtetris.ini", "w")
| |
| 1215 | ||
| 1216 | if myEvent then | |
| 1217 | myEvent.writeLine("NoIntro = ")
| |
| 1218 | myEvent.writeLine("NoMonitor = ")
| |
| 1219 | myEvent.writeLine("NoMusic = ")
| |
| 1220 | myEvent.writeLine("DefaultMonitorSide = ")
| |
| 1221 | myEvent.writeLine("DefaultSpeed = ")
| |
| 1222 | myEvent.writeLine("DefaultLevel = ")
| |
| 1223 | myEvent.writeLine("DefaultMode = ")
| |
| 1224 | myEvent.close() | |
| 1225 | else canSave = false end | |
| 1226 | end | |
| 1227 | ||
| 1228 | -- Load saved data. | |
| 1229 | if fs.exists(shell.resolve(".").."\\bbtetris.dat") then
| |
| 1230 | myEvent = fs.open(shell.resolve(".").."\\bbtetris.dat", "r")
| |
| 1231 | highScore = myEvent.readLine() | |
| 1232 | highScore = textutils.unserialize(myEvent.readLine()) | |
| 1233 | saves = textutils.unserialize(myEvent.readLine()) | |
| 1234 | myEvent.close() | |
| 1235 | end | |
| 1236 | ||
| 1237 | if type(highScore) == "table" then | |
| 1238 | for i=#highScore+1,8 do highScore[i] = 0 end | |
| 1239 | else | |
| 1240 | highScore = {}
| |
| 1241 | for i=1,8 do highScore[i] = 0 end | |
| 1242 | end | |
| 1243 | ||
| 1244 | -- Look for a monitor to use. | |
| 1245 | if not skipMonitor then | |
| 1246 | if defaultMonitor then | |
| 1247 | if peripheral.getType(defaultMonitor) == "monitor" and peripheral.call(defaultMonitor, "isColour") then | |
| 1248 | term.clear() | |
| 1249 | term.setCursorPos(1,1) | |
| 1250 | print("Game in progress on attached display...")
| |
| 1251 | ||
| 1252 | mon = peripheral.wrap(defaultMonitor) | |
| 1253 | mon.side = defaultMonitor | |
| 1254 | if not term.restore then mon.restoreTo = term.current() end | |
| 1255 | term.redirect(mon) | |
| 1256 | enforceScreenSize() | |
| 1257 | else | |
| 1258 | exitGame("The \"monitor\" at location \""..defaultMonitor.."\" (specified in \"bbtetris.ini\") is invalid. Please fix that.")
| |
| 1259 | end | |
| 1260 | else | |
| 1261 | local sides = peripheral.getNames() | |
| 1262 | ||
| 1263 | for i=1,#sides do if peripheral.getType(sides[i]) == "monitor" and peripheral.call(sides[i], "isColour") then | |
| 1264 | print("")
| |
| 1265 | - | while true do |
| 1265 | + | |
| 1266 | - | myEvent = {os.pullEvent("char")}
|
| 1266 | + | |
| 1267 | - | |
| 1267 | + | |
| 1268 | - | if myEvent[2]:lower() == "y" then |
| 1268 | + | |
| 1269 | ||
| 1270 | mon = peripheral.wrap(sides[i]) | |
| 1271 | mon.side = sides[i] | |
| 1272 | if not term.restore then mon.restoreTo = term.current() end | |
| 1273 | term.redirect(mon) | |
| 1274 | enforceScreenSize() | |
| 1275 | break | |
| 1276 | end end | |
| 1277 | end | |
| 1278 | - | break |
| 1278 | + | |
| 1279 | - | elseif myEvent[2]:lower() == "n" then |
| 1279 | + | |
| 1280 | - | break |
| 1280 | + | |
| 1281 | screenx,screeny = term.getSize() | |
| 1282 | pocket, depth = screenx < 50, screeny > 19 and 20 or 19 | |
| 1283 | if (screenx < 26 or screeny < 19) and not pocket then error("\nA minimum display resolution of 26 columns by 19 rows is required.\n\nIf you're trying to run me on eg a turtle, please try a regular computer.\n",0) end
| |
| 1284 | screenx,screeny = math.floor(screenx/2)-10, pocket and 0 or math.floor(screeny/2)-9 | |
| 1285 | ||
| 1286 | -- Load the music player, if possible. | |
| 1287 | if peripheral.find and peripheral.find("iron_note") and fs.exists("/moarp/note") and fs.exists(musicFile) then os.loadAPI("/moarp/note") end
| |
| 1288 | ||
| 1289 | -- Show the splash screen. | |
| 1290 | if not skipIntro then intro() end | |
| 1291 | ||
| 1292 | --------------------------------------------- | |
| 1293 | ------------ Main Program Loop ------------ | |
| 1294 | --------------------------------------------- | |
| 1295 | ||
| 1296 | while true do | |
| 1297 | drawBorder() | |
| 1298 | menu() | |
| 1299 | if note then parallel.waitForAny(game, note.songEngine) else game() end | |
| 1300 | end |