SHOW:
|
|
- or go back to the newest paste.
| 1 | --[[ | |
| 2 | - | Gold Runner |
| 2 | + | Code Runner |
| 3 | - | Inspired by the game by Doug Smith (C) 1983 |
| 3 | + | Inspired by the game by Doug fKqTDD5r |
| 4 | ||
| 5 | Written by: Nitrogen Fingers | |
| 6 | ]]-- | |
| 7 | ||
| 8 | running = true | |
| 9 | started = false | |
| 10 | nextLevel = false | |
| 11 | ||
| 12 | local drawOffsetX = 1 | |
| 13 | local drawOffsetY = 0 | |
| 14 | ||
| 15 | local map = {}
| |
| 16 | local goldMap = {}
| |
| 17 | local blockTimers = {}
| |
| 18 | local blockIntv = 5 | |
| 19 | ||
| 20 | local monks = {}
| |
| 21 | local monkTimer = -1 | |
| 22 | local monkSpawnIntv = 3 | |
| 23 | local monkTrapIntv = blockIntv/2 | |
| 24 | ||
| 25 | local goldCount = 0 | |
| 26 | local maxGoldCount = 0 | |
| 27 | local playerLives = 3 | |
| 28 | local playerScore = 0 | |
| 29 | local plspawnX = 0 | |
| 30 | local plspawnY = 0 | |
| 31 | ||
| 32 | local plX = 0 | |
| 33 | local plY = 0 | |
| 34 | local pfalling = false | |
| 35 | local moveTimer = -1 | |
| 36 | local shootTimer = -1 | |
| 37 | local spawnTimer = -1 | |
| 38 | local moveIntv = 0.15 | |
| 39 | ||
| 40 | local exX = 0 | |
| 41 | local exY = 0 | |
| 42 | ||
| 43 | local levelList = {}
| |
| 44 | local currentLevel = 1 | |
| 45 | ||
| 46 | local function loadMap(_sPath) | |
| 47 | if not fs.exists(_sPath) then return end | |
| 48 | map = {}
| |
| 49 | goldMap = {}
| |
| 50 | monks = {}
| |
| 51 | goldCount = 0 | |
| 52 | ||
| 53 | local file = fs.open(_sPath, "r") | |
| 54 | local line = file:readLine() | |
| 55 | while line do | |
| 56 | goldMap[#map+1] = {}
| |
| 57 | map[#map+1] = {}
| |
| 58 | for i=1,math.min(#line,49) do | |
| 59 | local lchar = string.sub(line,i,i) | |
| 60 | if tonumber(lchar, 16) then | |
| 61 | lchar = math.pow(2, tonumber(lchar,16)) | |
| 62 | ||
| 63 | if lchar == colours.blue then | |
| 64 | map[#map][i] = 0 | |
| 65 | elseif lchar == colours.brown then | |
| 66 | map[#map][i] = 'H' | |
| 67 | elseif lchar == colours.yellow then | |
| 68 | goldMap[#map][i] = 1 | |
| 69 | goldCount = goldCount + 1 | |
| 70 | elseif lchar == colours.orange then | |
| 71 | map[#map][i] = 0 | |
| 72 | goldMap[#map][i] = 1 | |
| 73 | goldCount = goldCount + 1 | |
| 74 | elseif lchar == colours.green then | |
| 75 | map[#map][i] = '-' | |
| 76 | elseif lchar == colours.lightGrey then | |
| 77 | map[#map][i] = 'h' | |
| 78 | elseif lchar == colours.grey then | |
| 79 | map[#map][i] = '#' | |
| 80 | elseif lchar == colours.white then | |
| 81 | plX = i | |
| 82 | plspawnX = i | |
| 83 | plY = #map | |
| 84 | plspawnY = #map | |
| 85 | elseif lchar == colours.lime then | |
| 86 | exX = i | |
| 87 | exY = #map | |
| 88 | elseif lchar == colours.red then | |
| 89 | table.insert(monks, {
| |
| 90 | --X and Y, clear enough | |
| 91 | x = i, y = #map; | |
| 92 | --Where they spawn when they die | |
| 93 | spawnX = i, spawnY = #map; | |
| 94 | -- Any gold they're carring- it's a 1 in 5 | |
| 95 | gold = false; | |
| 96 | -- Whether or not they're falling | |
| 97 | falling = false; | |
| 98 | -- Timer if they're dead to respawn | |
| 99 | dead = nil; | |
| 100 | --Whether or not the monk has just spawned | |
| 101 | justSpawned = true; | |
| 102 | --Whether or not the monk has just escaped | |
| 103 | justEscaped = false; | |
| 104 | -- Current aim- it's "up", "down", "across" or "none" | |
| 105 | behaviour = "none"; | |
| 106 | -- The desired x position to travel to, when one is necessary. | |
| 107 | desX = nil; | |
| 108 | -- The escape timer | |
| 109 | trapped = nil; | |
| 110 | }) | |
| 111 | end | |
| 112 | end | |
| 113 | end | |
| 114 | if #map == 18 then break end | |
| 115 | line = file:readLine() | |
| 116 | end | |
| 117 | file:close() | |
| 118 | maxGoldCount = goldCount | |
| 119 | return true | |
| 120 | end | |
| 121 | ||
| 122 | --When something moves or something needs to be drawn, we | |
| 123 | --just change the appropriate tile with this method. | |
| 124 | local function updateMap(x,y) | |
| 125 | term.setCursorPos(x + drawOffsetX, y + drawOffsetY) | |
| 126 | term.setBackgroundColour(colours.black) | |
| 127 | if plX == x and plY == y and map[y][x] ~= 0 then | |
| 128 | term.setTextColour(colours.white) | |
| 129 | if map[y][x] == 1 then term.setBackgroundColour(colours.lightBlue) end | |
| 130 | term.write("&")
| |
| 131 | elseif map[y][x] == 'H' or (map[y][x] == 'h' and | |
| 132 | goldCount == 0) then | |
| 133 | term.setTextColour(colours.brown) | |
| 134 | term.write("H")
| |
| 135 | elseif map[y][x] == '-' then | |
| 136 | term.setTextColour(colours.brown) | |
| 137 | term.write(map[y][x]) | |
| 138 | elseif map[y][x] == '#' then | |
| 139 | term.setBackgroundColour(colours.grey) | |
| 140 | term.write(" ")
| |
| 141 | elseif type(map[y][x]) == "number" then | |
| 142 | local uchar = ' ' | |
| 143 | if map[y][x] == 3 then | |
| 144 | term.setBackgroundColour(colours.lightBlue) | |
| 145 | elseif map[y][x] == 2 and goldMap[y][x] == 1 then | |
| 146 | term.setTextColour(colours.yellow) | |
| 147 | uchar = '$' | |
| 148 | elseif map[y][x] == 1 then | |
| 149 | term.setBackgroundColour(colours.lightBlue) | |
| 150 | elseif map[y][x] == 0 then | |
| 151 | term.setBackgroundColour(colours.blue) | |
| 152 | end | |
| 153 | term.write(uchar) | |
| 154 | elseif goldMap[y][x] == 1 then | |
| 155 | term.setTextColour(colours.yellow) | |
| 156 | term.write('$')
| |
| 157 | elseif exX == x and exY == y and goldCount == 0 then | |
| 158 | term.setTextColour(colours.lime) | |
| 159 | term.write("@")
| |
| 160 | else | |
| 161 | term.write(" ")
| |
| 162 | end | |
| 163 | end | |
| 164 | ||
| 165 | --It's silly to iterate through all monks when drawing tiles, so | |
| 166 | --we do it separately. | |
| 167 | local function drawMonk(monk) | |
| 168 | term.setCursorPos(monk.x + drawOffsetX, monk.y + drawOffsetY) | |
| 169 | if monk.justSpawned then term.setTextColour(colours.pink) | |
| 170 | else term.setTextColour(colours.red) end | |
| 171 | if map[monk.y][monk.x] == 1 then term.setBackgroundColour(colours.lightBlue) | |
| 172 | else term.setBackgroundColour(colours.black) end | |
| 173 | term.write("&")
| |
| 174 | end | |
| 175 | ||
| 176 | --Draws the map for the first time. It barely changes, so we really | |
| 177 | --only call this the once. | |
| 178 | local function drawMap() | |
| 179 | for y=1,#map do | |
| 180 | for x=1,49 do | |
| 181 | updateMap(x,y) | |
| 182 | end | |
| 183 | end | |
| 184 | for _,monk in pairs(monks) do drawMonk(monk)end | |
| 185 | end | |
| 186 | ||
| 187 | --When all coins have been collected, we add in invisble ladders and | |
| 188 | --the end game portal. | |
| 189 | local function drawEndgameMap() | |
| 190 | for y=1,#map do | |
| 191 | for x=1,49 do | |
| 192 | if map[y][x] == 'h' or (exX == x and exY == y) then | |
| 193 | updateMap(x,y) | |
| 194 | end | |
| 195 | end | |
| 196 | end | |
| 197 | end | |
| 198 | ||
| 199 | --Sets the map back to defaults, so we can start afresh | |
| 200 | local function resetMap() | |
| 201 | goldCount = maxGoldCount | |
| 202 | for i=1,#goldMap do | |
| 203 | for j=1,49 do | |
| 204 | if goldMap[i][j] == 0 then goldMap[i][j] = 1 end | |
| 205 | end | |
| 206 | end | |
| 207 | for _,monk in pairs(monks) do | |
| 208 | monk.justSpawned = true | |
| 209 | monk.dead = nil | |
| 210 | monk.trapped = nil | |
| 211 | monk.justEscaped = false | |
| 212 | monk.falling = false | |
| 213 | monk.behaviour = "none" | |
| 214 | monk.x = monk.spawnX | |
| 215 | monk.y = monk.spawnY | |
| 216 | end | |
| 217 | ||
| 218 | for _,timer in pairs(blockTimers) do | |
| 219 | map[timer.y][timer.x] = 0 | |
| 220 | end | |
| 221 | blockTimers = {}
| |
| 222 | plX = plspawnX | |
| 223 | plY = plspawnY | |
| 224 | ||
| 225 | moveTimer = -1 | |
| 226 | shootTimer = -1 | |
| 227 | spawnTimer = -1 | |
| 228 | monkTimer = -1 | |
| 229 | pfalling = false | |
| 230 | end | |
| 231 | ||
| 232 | --Draws the HUD. This also rarely changes, so we update it when something happens. | |
| 233 | local function drawHUD() | |
| 234 | term.setCursorPos(2,19) | |
| 235 | term.setBackgroundColour(colours.black) | |
| 236 | term.clearLine() | |
| 237 | term.setTextColour(colours.blue) | |
| 238 | term.write("Score: ")
| |
| 239 | term.setTextColour(colours.yellow) | |
| 240 | term.write(string.rep("0", 5-math.floor(math.log10(playerScore + 1)))
| |
| 241 | ..playerScore) | |
| 242 | term.setTextColour(colours.yellow) | |
| 243 | term.setCursorPos(25 - #levelList[currentLevel]/2, 19) | |
| 244 | term.write(levelList[currentLevel]) | |
| 245 | local lstr = "Men: " | |
| 246 | term.setCursorPos(50 - #lstr - math.floor(math.log10(playerLives)), 19) | |
| 247 | term.setTextColour(colours.blue) | |
| 248 | term.write(lstr) | |
| 249 | term.setTextColour(colours.yellow) | |
| 250 | term.write(playerLives.."") | |
| 251 | end | |
| 252 | ||
| 253 | --Checks to see if any given desired move is legal. Monks and players both use this. | |
| 254 | local function isLegalMove(initX,initY,finX,finY) | |
| 255 | if finY < 1 or finY > #map or finX < 1 or finX > 49 then | |
| 256 | return false | |
| 257 | end | |
| 258 | ||
| 259 | if map[finY][finX] ~= 0 and map[finY][finX] ~= '#' then | |
| 260 | --This reports 'self moves' as being illegal, but that's fine | |
| 261 | for _,monk in pairs(monks) do | |
| 262 | if monk.x == finX and monk.y == finY then return false end | |
| 263 | end | |
| 264 | ||
| 265 | - | map[finY][finX] == "-") |
| 265 | + | |
| 266 | then return true | |
| 267 | elseif finY == initY+1 and (map[finY][finX] == "H" or (map[finY][finX] == "h" and goldCount == 0) | |
| 268 | or (type(map[finY][finX]) == "number" and map[finY][finX] > 0) or map[finY][finX] == nil or | |
| 269 | map[finY][finX] == "-" or (map[finY][finX] == 'h' and goldCount ~= 0)) | |
| 270 | then return true | |
| 271 | elseif finX == initX-1 or finX == initX+1 then return true | |
| 272 | end | |
| 273 | end | |
| 274 | end | |
| 275 | ||
| 276 | --Moves the player to a given step. | |
| 277 | local function movePlayer(x,y,ignoreLegal) | |
| 278 | if not ignoreLegal and not isLegalMove(plX,plY,x,y) then return false end | |
| 279 | ||
| 280 | local ox = plX | |
| 281 | local oy = plY | |
| 282 | plX = x | |
| 283 | plY = y | |
| 284 | ||
| 285 | updateMap(ox,oy) | |
| 286 | updateMap(x,y) | |
| 287 | if goldMap[y][x] == 1 then | |
| 288 | goldMap[y][x] = 0 | |
| 289 | goldCount = goldCount - 1 | |
| 290 | playerScore = playerScore + 5 | |
| 291 | if playerScore % 200 == 0 then playerLives = playerLives + 1 end | |
| 292 | drawHUD() | |
| 293 | if (goldCount == 0) then | |
| 294 | drawEndgameMap() | |
| 295 | end | |
| 296 | elseif exX == plX and exY == plY and goldCount == 0 then | |
| 297 | started = false | |
| 298 | nextLevel = true | |
| 299 | end | |
| 300 | ||
| 301 | pfalling = (y < #map and map[y][x] ~= '-' and map[y][x] ~= 'H' and not (map[y][x] == 'h' and goldCount == 0) | |
| 302 | and (map[y+1][x] == nil or map[y+1][x] == 2 or map[y+1][x] == '-')) | |
| 303 | if (map[y+1][x] == 'h' and goldCount ~= 0) then pfalling = true end | |
| 304 | for _,monk in pairs(monks) do | |
| 305 | if monk.x == plX and monk.y == plY + 1 then pfalling = false break end | |
| 306 | end | |
| 307 | return true | |
| 308 | end | |
| 309 | ||
| 310 | local function updateMonks() | |
| 311 | for _,monk in pairs(monks) do | |
| 312 | --Absolute first step- if he's trapped or dead, he's going nowhere | |
| 313 | if monk.trapped or monk.dead then | |
| 314 | --If he's just spawned he takes a second to orient himself | |
| 315 | elseif monk.justSpawned then | |
| 316 | monk.justSpawned = false | |
| 317 | --We evaluate their falling behaviour here (as freed monks CAN stand on air) | |
| 318 | monk.falling = (monk.y < #map and map[monk.y][monk.x] ~= '-' and (map[monk.y+1][monk.x] == nil or | |
| 319 | map[monk.y+1][monk.x] == 2 or map[monk.y+1][monk.x] == '-') and type(map[monk.y][monk.x] ~= "number")) | |
| 320 | for _,omonk in pairs(monks) do | |
| 321 | if omonk.x == monk.x and omonk.y == monk.y + 1 then monk.falling = false break end | |
| 322 | end | |
| 323 | if monk.x == plX and monk.y == plY + 1 then monk.falling = false end | |
| 324 | --Then we consider if he's just gotten out of a hole | |
| 325 | elseif monk.justEscaped then | |
| 326 | monk.justEscaped = false | |
| 327 | --He tries the player side first | |
| 328 | local playerSide = (plX-monk.x) / math.abs(plX-monk.x) | |
| 329 | if isLegalMove(monk.x, monk.y, monk.x + playerSide, monk.y) then | |
| 330 | monk.x = monk.x + playerSide | |
| 331 | updateMap(monk.x - playerSide, monk.y) | |
| 332 | elseif isLegalMove(monk.x, monk.y, monk.x - playerSide, monk.y) then | |
| 333 | monk.x = monk.x - playerSide | |
| 334 | updateMap(monk.x + playerSide, monk.y) | |
| 335 | end | |
| 336 | drawMonk(monk) | |
| 337 | --Then we evaluate falling | |
| 338 | elseif monk.falling then | |
| 339 | monk.behaviour = "none" | |
| 340 | monk.y = monk.y + 1 | |
| 341 | updateMap(monk.x, monk.y-1) | |
| 342 | drawMonk(monk) | |
| 343 | monk.desX = nil | |
| 344 | if type(map[monk.y][monk.x]) == "number" then | |
| 345 | monk.trapped = os.startTimer(monkTrapIntv) | |
| 346 | monk.falling = false | |
| 347 | else | |
| 348 | monk.falling = (monk.y < #map and map[monk.y][monk.x] ~= '-' and (map[monk.y+1][monk.x] == nil or | |
| 349 | map[monk.y+1][monk.x] == 2 or map[monk.y+1][monk.x] == '-') and type(map[monk.y][monk.x] ~= "number")) | |
| 350 | for _,omonk in pairs(monks) do | |
| 351 | if omonk.x == monk.x and omonk.y == monk.y + 1 then monk.falling = false break end | |
| 352 | end | |
| 353 | if monk.x == plX and monk.y == plY + 1 then monk.falling = false end | |
| 354 | if monk.justEscaped then monk.falling = false end | |
| 355 | end | |
| 356 | --If he's on his feet and not trapped, he's allowed to think about where to move | |
| 357 | elseif monk.y == plY then | |
| 358 | --Is the monk on the same level as the player? How lucky! They'll just walk towards him | |
| 359 | monk.desX = plX | |
| 360 | monk.behaviour = "across" | |
| 361 | --Y difference takes precedence over X (as in the original, makes them a bit smarter) | |
| 362 | elseif monk.y < plY then | |
| 363 | --If they can move up, they will | |
| 364 | if isLegalMove(monk.x,monk.y,monk.x,monk.y+1) and not monk.justEscaped then | |
| 365 | monk.y = monk.y+1 | |
| 366 | updateMap(monk.x, monk.y-1) | |
| 367 | drawMonk(monk) | |
| 368 | monk.desX = nil | |
| 369 | --A down move can lead to a fall, so we check if they're now falling. | |
| 370 | monk.falling = (monk.y < #map and map[monk.y][monk.x] ~= '-' and (map[monk.y+1][monk.x] == nil or | |
| 371 | map[monk.y+1][monk.x] == 2 or map[monk.y+1][monk.x] == '-') and type(map[monk.y][monk.x] ~= "number")) | |
| 372 | monk.falling = (monk.y < #map and map[monk.y][monk.x] ~= '-' and (map[monk.y+1][monk.x] == nil or | |
| 373 | map[monk.y+1][monk.x] == 2 or map[monk.y+1][monk.x] == '-') and type(map[monk.y][monk.x] ~= "number")) | |
| 374 | for _,omonk in pairs(monks) do | |
| 375 | if omonk.x == monk.x and omonk.y == monk.y + 1 then monk.falling = false break end | |
| 376 | end | |
| 377 | if monk.x == plX and monk.y == plY + 1 then monk.falling = false end | |
| 378 | --Otherwise, it's off to the nearest ladder, monkey bars or perilous ledge to jump off | |
| 379 | --assuming they haven't found one already | |
| 380 | elseif monk.desX == nil then | |
| 381 | if monk.behaviour ~= "down" then monk.desX = nil end | |
| 382 | monk.behaviour = "down" | |
| 383 | monk.desX = nil | |
| 384 | local cmLeft = true | |
| 385 | local cmRight = true | |
| 386 | --We try to find the nearest by searching alternate left and right at variable distance | |
| 387 | for i=1,math.max(monk.x - 1, 49 - monk.x) do | |
| 388 | if monk.x-i > 0 and cmLeft then | |
| 389 | --If a wall blocks the monks path, they can't keep going left or right | |
| 390 | cmLeft = map[monk.y][monk.x-i] ~= 0 | |
| 391 | --But if it's all clear, they look for something to climb/jump down | |
| 392 | if cmLeft and (map[monk.y+1][monk.x-i] == "H" or (map[monk.y+1][monk.x-i] == 'h' and goldCount == 0) | |
| 393 | or map[monk.y+1][monk.x-i] == nil or map[monk.y][monk.x-i] == '-') then | |
| 394 | monk.desX = monk.x-i | |
| 395 | break | |
| 396 | end | |
| 397 | end | |
| 398 | if monk.x+i < 50 and cmRight then | |
| 399 | --If a wall blocks the monks path, they can't keep going left or right | |
| 400 | cmRight = map[monk.y][monk.x+i] ~= 0 | |
| 401 | --But if it's all clear, they look for something to climb/jump down | |
| 402 | if cmRight and (map[monk.y+1][monk.x+i] == "H" or (map[monk.y+1][monk.x+i] == 'h' and goldCount == 0) | |
| 403 | or map[monk.y+1][monk.x+i] == nil or map[monk.y][monk.x+i] == '-') then | |
| 404 | monk.desX = monk.x+i | |
| 405 | break | |
| 406 | end | |
| 407 | end | |
| 408 | end | |
| 409 | end | |
| 410 | elseif monk.y > plY then | |
| 411 | if monk.behaviour ~= "up" then monk.desX = nil end | |
| 412 | monk.behaviour = "up" | |
| 413 | --Same deal again- try moving up first | |
| 414 | if isLegalMove(monk.x,monk.y,monk.x,monk.y-1) then | |
| 415 | monk.y = monk.y-1 | |
| 416 | updateMap(monk.x, monk.y+1) | |
| 417 | drawMonk(monk) | |
| 418 | monk.desX = nil | |
| 419 | --You can never move up and start falling, so we don't bother to check | |
| 420 | --Otherwise they need ladders to climb up | |
| 421 | elseif monk.desX == nil then | |
| 422 | monk.behaviour = "up" | |
| 423 | monk.desX = nil | |
| 424 | local cmLeft = true | |
| 425 | local cmRight = true | |
| 426 | --We try to find the nearest by searching alternate left and right at variable distance | |
| 427 | for i=1,math.max(monk.x - 1, 49 - monk.x) do | |
| 428 | if monk.x-i > 0 and cmLeft then | |
| 429 | --If a wall blocks the monks path or a pit is in the way, they can't keep going left or right | |
| 430 | cmLeft = map[monk.y][monk.x-i] ~= 0 and (monk.y == #map or map[monk.y+1][monk.x-i] ~= nil | |
| 431 | or map[monk.y][monk.x-i] == '-') | |
| 432 | --But if it's all clear, they look for a ladder | |
| 433 | if cmLeft and (map[monk.y][monk.x-i] == "H" or (map[monk.y][monk.x-i] == 'h' and goldCount == 0)) then | |
| 434 | monk.desX = monk.x-i | |
| 435 | break | |
| 436 | end | |
| 437 | end | |
| 438 | if monk.x+i < 50 and cmRight then | |
| 439 | cmRight = map[monk.y][monk.x+i] ~= 0 and (monk.y == #map or map[monk.y+1][monk.x+i] ~= nil | |
| 440 | or map[monk.y][monk.x+i] == '-') | |
| 441 | if cmRight and (map[monk.y][monk.x+i] == "H" or (map[monk.y][monk.x+i] == 'h' and goldCount == 0)) then | |
| 442 | monk.desX = monk.x+i | |
| 443 | break | |
| 444 | end | |
| 445 | end | |
| 446 | end | |
| 447 | end | |
| 448 | end | |
| 449 | ||
| 450 | if not (monk.trapped or monk.dead) then | |
| 451 | --Has the monk decided on moving left or right? If so we try to move him | |
| 452 | if monk.desX and not monk.falling then | |
| 453 | local mdir = monk.desX - monk.x | |
| 454 | local mdir = mdir / math.abs(mdir) | |
| 455 | if isLegalMove(monk.x,monk.y,monk.x+mdir,monk.y) then | |
| 456 | monk.x = monk.x + mdir | |
| 457 | updateMap(monk.x - mdir, monk.y) | |
| 458 | drawMonk(monk) | |
| 459 | else | |
| 460 | --This allows re-evaluations if they get stuck- not ideal but good enough | |
| 461 | monk.desX = nil | |
| 462 | end | |
| 463 | end | |
| 464 | monk.falling = (monk.y < #map and map[monk.y][monk.x] ~= '-' and (map[monk.y+1][monk.x] == nil or | |
| 465 | map[monk.y+1][monk.x] == 2 or map[monk.y+1][monk.x] == '-') and type(map[monk.y][monk.x] ~= "number")) | |
| 466 | for _,omonk in pairs(monks) do | |
| 467 | if omonk.x == monk.x and omonk.y == monk.y + 1 then monk.falling = false break end | |
| 468 | end | |
| 469 | if monk.x == plX and monk.y == plY + 1 then monk.falling = false end | |
| 470 | --We have caught and killed the player | |
| 471 | if monk.x == plX and monk.y == plY and spawnTimer == -1 then | |
| 472 | spawnTimer = os.startTimer(2) | |
| 473 | end | |
| 474 | end | |
| 475 | end | |
| 476 | end | |
| 477 | ||
| 478 | local function updateBlockTimer(tid) | |
| 479 | local remAt = nil | |
| 480 | for i,v in ipairs(blockTimers) do | |
| 481 | if v.timer == tid then | |
| 482 | if map[v.y][v.x] == 3 then | |
| 483 | map[v.y][v.x] = 2 | |
| 484 | v.timer = os.startTimer(blockIntv) | |
| 485 | elseif map[v.y][v.x] == 2 then | |
| 486 | map[v.y][v.x] = 1 | |
| 487 | v.timer = os.startTimer(0.1) | |
| 488 | elseif map[v.y][v.x] == 1 then | |
| 489 | map[v.y][v.x] = 0 | |
| 490 | --If the player is caught in a block, he dies | |
| 491 | if v.y == plY and v.x == plX then | |
| 492 | spawnTimer = os.startTimer(2) | |
| 493 | end | |
| 494 | for _,monk in pairs(monks) do | |
| 495 | if monk.x == v.x and monk.y == v.y then | |
| 496 | monk.dead = os.startTimer(monkSpawnIntv) | |
| 497 | --Easiest way to get them out of the way rather than evaluation | |
| 498 | monk.x = -1 | |
| 499 | monk.y = -1 | |
| 500 | monk.trapped = nil | |
| 501 | end | |
| 502 | end | |
| 503 | remAt = i | |
| 504 | end | |
| 505 | updateMap(v.x,v.y) | |
| 506 | break | |
| 507 | end | |
| 508 | end | |
| 509 | if remAt then table.remove(blockTimers,remAt) end | |
| 510 | end | |
| 511 | ||
| 512 | local function shootBlock(x,y) | |
| 513 | if y <= #map and map[y][x] == 0 and (map[y-1][x] == nil | |
| 514 | or map[y-1][x] == 2 or (map[y-1][x] == 'h' and goldCount > 0)) then | |
| 515 | map[y][x] = 3 | |
| 516 | table.insert(blockTimers, {x = x; y = y; timer = os.startTimer(0.1);} )
| |
| 517 | updateMap(x,y) | |
| 518 | end | |
| 519 | end | |
| 520 | ||
| 521 | local function handleEvents() | |
| 522 | local id,p1,p2,p3 = os.pullEvent() | |
| 523 | ||
| 524 | if id == "key" then | |
| 525 | if p1 == keys.a and moveTimer == -1 and spawnTimer == -1 then | |
| 526 | movePlayer(plX-1,plY) | |
| 527 | moveTimer = os.startTimer(moveIntv) | |
| 528 | elseif p1 == keys.d and moveTimer == -1 and spawnTimer == -1 then | |
| 529 | movePlayer(plX+1,plY) | |
| 530 | moveTimer = os.startTimer(moveIntv) | |
| 531 | elseif p1 == keys.w and moveTimer == -1 and spawnTimer == -1 then | |
| 532 | movePlayer(plX,plY-1) | |
| 533 | moveTimer = os.startTimer(moveIntv) | |
| 534 | elseif p1 == keys.s and moveTimer == -1 and spawnTimer == -1 then | |
| 535 | movePlayer(plX,plY+1) | |
| 536 | moveTimer = os.startTimer(moveIntv) | |
| 537 | elseif p1 == keys.q and shootTimer == -1 and not pfalling and spawnTimer == -1 then | |
| 538 | shootBlock(plX-1,plY+1) | |
| 539 | shootTimer = os.startTimer(moveIntv) | |
| 540 | elseif p1 == keys.e and shootTimer == -1 and not pfalling and spawnTimer == -1 then | |
| 541 | shootBlock(plX+1,plY+1) | |
| 542 | shootTimer = os.startTimer(moveIntv) | |
| 543 | elseif p1 == keys.enter then | |
| 544 | started = false | |
| 545 | elseif p1 == keys.t then | |
| 546 | started = false | |
| 547 | running = false | |
| 548 | end | |
| 549 | elseif id == "timer" then | |
| 550 | if p1 == shootTimer then shootTimer = -1 | |
| 551 | elseif p1 == spawnTimer then | |
| 552 | started = false | |
| 553 | elseif p1 == moveTimer then | |
| 554 | if pfalling then | |
| 555 | movePlayer(plX,plY+1) | |
| 556 | moveTimer = os.startTimer(moveIntv) | |
| 557 | else | |
| 558 | moveTimer = -1 | |
| 559 | end | |
| 560 | elseif p1 == monkTimer then | |
| 561 | updateMonks() | |
| 562 | monkTimer = os.startTimer(moveIntv * 2) | |
| 563 | elseif updateBlockTimer(p1) then | |
| 564 | else | |
| 565 | for _,monk in pairs(monks) do | |
| 566 | if p1 == monk.trapped then | |
| 567 | --You can stand on a monk to force them to be killed- so we check for that | |
| 568 | --along with being buried in tunnels, etc. | |
| 569 | local stillTrapped = map[monk.y-1][monk.x] == 0 or (plX == monk.x and plY == monk.y-1) | |
| 570 | for _,omonk in pairs(monks) do | |
| 571 | if omonk.x == monk.x and omonk.y == monk.y-1 then | |
| 572 | stillTrapped = true | |
| 573 | break | |
| 574 | end | |
| 575 | end | |
| 576 | --Perpetually trapped monks will try to excape much more quickly | |
| 577 | if stillTrapped then | |
| 578 | --This needs to be tweaked | |
| 579 | monk.trapped = os.startTimer(0.75) | |
| 580 | else | |
| 581 | --When free, they head in your general direction, re-evaluate later | |
| 582 | monk.y = monk.y - 1 | |
| 583 | --This is necessary to stop 'double jumping' | |
| 584 | monk.desX = nil | |
| 585 | monk.trapped = nil | |
| 586 | monk.behaviour = "none" | |
| 587 | monk.justEscaped = true | |
| 588 | ||
| 589 | updateMap(monk.x, monk.y+1) | |
| 590 | drawMonk(monk) | |
| 591 | end | |
| 592 | break | |
| 593 | elseif p1 == monk.dead then | |
| 594 | --Same deal- you can camp spawn | |
| 595 | local stillDead = plX == monk.spawnX and plY == monk.spawnY | |
| 596 | for _,omonk in pairs(monks) do | |
| 597 | if omonk.x == monk.spawnX and omonk.y == monk.spawnY then | |
| 598 | stillDead = true | |
| 599 | break | |
| 600 | end | |
| 601 | end | |
| 602 | --They'll spawn the second you give them the chance | |
| 603 | if stillDead then | |
| 604 | monk.dead = os.startTimer(0.5) | |
| 605 | else | |
| 606 | monk.x = monk.spawnX | |
| 607 | monk.y = monk.spawnY | |
| 608 | monk.dead = nil | |
| 609 | monk.justSpawned = true | |
| 610 | monk.behaviour = "none" | |
| 611 | drawMonk(monk) | |
| 612 | break | |
| 613 | end | |
| 614 | end | |
| 615 | end | |
| 616 | end | |
| 617 | end | |
| 618 | end | |
| 619 | ||
| 620 | term.clear() | |
| 621 | if not fs.exists(shell.resolve(".").."/levels") then
| |
| 622 | error("Level directory not present!")
| |
| 623 | end | |
| 624 | levelList = fs.list(shell.resolve(".").."/levels")
| |
| 625 | if #levelList == 0 then | |
| 626 | error("Level directory is empty!")
| |
| 627 | end | |
| 628 | ||
| 629 | loadMap(shell.resolve(".").."/levels/"..levelList[currentLevel])
| |
| 630 | while running do | |
| 631 | drawMap() | |
| 632 | drawHUD() | |
| 633 | os.pullEvent("key")
| |
| 634 | monkTimer = os.startTimer(moveIntv * 1.5) | |
| 635 | ||
| 636 | started = true | |
| 637 | while started do | |
| 638 | handleEvents() | |
| 639 | end | |
| 640 | ||
| 641 | if nextLevel then | |
| 642 | if currentLevel == #levelList then | |
| 643 | running = false | |
| 644 | break | |
| 645 | else | |
| 646 | currentLevel = currentLevel + 1 | |
| 647 | resetMap() | |
| 648 | loadMap(shell.resolve(".").."/levels/"..levelList[currentLevel])
| |
| 649 | end | |
| 650 | nextLevel = false | |
| 651 | else | |
| 652 | playerLives = playerLives-1 | |
| 653 | if playerLives > 0 then resetMap() | |
| 654 | else running = false end | |
| 655 | end | |
| 656 | end | |
| 657 | ||
| 658 | if nextLevel then | |
| 659 | local msg = "All levels defeated, Code Runner!" | |
| 660 | term.setBackgroundColour(colours.black) | |
| 661 | term.setTextColour(colours.lime) | |
| 662 | term.setCursorPos(25 - #msg/2, 2) | |
| 663 | term.write(msg) | |
| 664 | else | |
| 665 | local msg = "Game over!" | |
| 666 | term.setBackgroundColour(colours.black) | |
| 667 | term.setTextColour(colours.red) | |
| 668 | term.setCursorPos(25 - #msg/2, 2) | |
| 669 | term.write(msg) | |
| 670 | end | |
| 671 | sleep(2) | |
| 672 | term.setCursorPos(19,51) | |
| 673 | print("") |