View difference between Paste ID: CWVmdV0Z and bGdCnPmp
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("")