SHOW:
|
|
- or go back to the newest paste.
1 | --[[ | |
2 | - | Code Runner |
2 | + | Gold Runner |
3 | - | Inspired by the game by Doug |
3 | + | Inspired by the game by Doug Smith (C) 1983 |
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 map[finY][finX] ~= 0 and map[finY][finX] ~= '#' then | |
256 | --This reports 'self moves' as being illegal, but that's fine | |
257 | for _,monk in pairs(monks) do | |
258 | if monk.x == finX and monk.y == finY then return false end | |
259 | end | |
260 | ||
261 | if finY == initY-1 and (map[initY][initX] == "H" or (map[initY][initX] == "h" and goldCount == 0)) | |
262 | then return true | |
263 | elseif finY == initY+1 and (map[finY][finX] == "H" or (map[finY][finX] == "h" and goldCount == 0) | |
264 | or (type(map[finY][finX]) == "number" and map[finY][finX] > 0) or map[finY][finX] == nil or | |
265 | map[finY][finX] == "-") | |
266 | then return true | |
267 | elseif finX == initX-1 or finX == initX+1 then return true | |
268 | end | |
269 | end | |
270 | end | |
271 | ||
272 | --Moves the player to a given step. | |
273 | local function movePlayer(x,y,ignoreLegal) | |
274 | if not ignoreLegal and not isLegalMove(plX,plY,x,y) then return false end | |
275 | ||
276 | local ox = plX | |
277 | local oy = plY | |
278 | plX = x | |
279 | plY = y | |
280 | ||
281 | updateMap(ox,oy) | |
282 | updateMap(x,y) | |
283 | if goldMap[y][x] == 1 then | |
284 | goldMap[y][x] = 0 | |
285 | goldCount = goldCount - 1 | |
286 | playerScore = playerScore + 5 | |
287 | if playerScore % 200 == 0 then playerLives = playerLives + 1 end | |
288 | drawHUD() | |
289 | if (goldCount == 0) then | |
290 | drawEndgameMap() | |
291 | end | |
292 | elseif exX == plX and exY == plY and goldCount == 0 then | |
293 | started = false | |
294 | nextLevel = true | |
295 | end | |
296 | ||
297 | pfalling = (y < #map and map[y][x] ~= '-' and map[y][x] ~= 'H' and not (map[y][x] == 'h' and goldCount == 0) | |
298 | and (map[y+1][x] == nil or map[y+1][x] == 2 or map[y+1][x] == '-')) | |
299 | for _,monk in pairs(monks) do | |
300 | if monk.x == plX and monk.y == plY + 1 then pfalling = false break end | |
301 | end | |
302 | return true | |
303 | end | |
304 | ||
305 | local function updateMonks() | |
306 | for _,monk in pairs(monks) do | |
307 | --Absolute first step- if he's trapped or dead, he's going nowhere | |
308 | if monk.trapped or monk.dead then | |
309 | --If he's just spawned he takes a second to orient himself | |
310 | elseif monk.justSpawned then | |
311 | monk.justSpawned = false | |
312 | --We evaluate their falling behaviour here (as freed monks CAN stand on air) | |
313 | monk.falling = (monk.y < #map and map[monk.y][monk.x] ~= '-' and (map[monk.y+1][monk.x] == nil or | |
314 | map[monk.y+1][monk.x] == 2 or map[monk.y+1][monk.x] == '-') and type(map[monk.y][monk.x] ~= "number")) | |
315 | for _,omonk in pairs(monks) do | |
316 | if omonk.x == monk.x and omonk.y == monk.y + 1 then monk.falling = false break end | |
317 | end | |
318 | if monk.x == plX and monk.y == plY + 1 then monk.falling = false end | |
319 | --Then we consider if he's just gotten out of a hole | |
320 | elseif monk.justEscaped then | |
321 | monk.justEscaped = false | |
322 | --He tries the player side first | |
323 | local playerSide = (plX-monk.x) / math.abs(plX-monk.x) | |
324 | if isLegalMove(monk.x, monk.y, monk.x + playerSide, monk.y) then | |
325 | monk.x = monk.x + playerSide | |
326 | updateMap(monk.x - playerSide, monk.y) | |
327 | elseif isLegalMove(monk.x, monk.y, monk.x - playerSide, monk.y) then | |
328 | monk.x = monk.x - playerSide | |
329 | updateMap(monk.x + playerSide, monk.y) | |
330 | end | |
331 | drawMonk(monk) | |
332 | --Then we evaluate falling | |
333 | elseif monk.falling then | |
334 | monk.behaviour = "none" | |
335 | monk.y = monk.y + 1 | |
336 | updateMap(monk.x, monk.y-1) | |
337 | drawMonk(monk) | |
338 | monk.desX = nil | |
339 | if type(map[monk.y][monk.x]) == "number" then | |
340 | monk.trapped = os.startTimer(monkTrapIntv) | |
341 | monk.falling = false | |
342 | else | |
343 | monk.falling = (monk.y < #map and map[monk.y][monk.x] ~= '-' and (map[monk.y+1][monk.x] == nil or | |
344 | map[monk.y+1][monk.x] == 2 or map[monk.y+1][monk.x] == '-') and type(map[monk.y][monk.x] ~= "number")) | |
345 | for _,omonk in pairs(monks) do | |
346 | if omonk.x == monk.x and omonk.y == monk.y + 1 then monk.falling = false break end | |
347 | end | |
348 | if monk.x == plX and monk.y == plY + 1 then monk.falling = false end | |
349 | if monk.justEscaped then monk.falling = false end | |
350 | end | |
351 | --If he's on his feet and not trapped, he's allowed to think about where to move | |
352 | elseif monk.y == plY then | |
353 | --Is the monk on the same level as the player? How lucky! They'll just walk towards him | |
354 | monk.desX = plX | |
355 | monk.behaviour = "across" | |
356 | --Y difference takes precedence over X (as in the original, makes them a bit smarter) | |
357 | elseif monk.y < plY then | |
358 | --If they can move up, they will | |
359 | if isLegalMove(monk.x,monk.y,monk.x,monk.y+1) and not monk.justEscaped then | |
360 | monk.y = monk.y+1 | |
361 | updateMap(monk.x, monk.y-1) | |
362 | drawMonk(monk) | |
363 | monk.desX = nil | |
364 | --A down move can lead to a fall, so we check if they're now falling. | |
365 | monk.falling = (monk.y < #map and map[monk.y][monk.x] ~= '-' and (map[monk.y+1][monk.x] == nil or | |
366 | map[monk.y+1][monk.x] == 2 or map[monk.y+1][monk.x] == '-') and type(map[monk.y][monk.x] ~= "number")) | |
367 | monk.falling = (monk.y < #map and map[monk.y][monk.x] ~= '-' and (map[monk.y+1][monk.x] == nil or | |
368 | map[monk.y+1][monk.x] == 2 or map[monk.y+1][monk.x] == '-') and type(map[monk.y][monk.x] ~= "number")) | |
369 | for _,omonk in pairs(monks) do | |
370 | if omonk.x == monk.x and omonk.y == monk.y + 1 then monk.falling = false break end | |
371 | end | |
372 | if monk.x == plX and monk.y == plY + 1 then monk.falling = false end | |
373 | --Otherwise, it's off to the nearest ladder, monkey bars or perilous ledge to jump off | |
374 | --assuming they haven't found one already | |
375 | elseif monk.desX == nil then | |
376 | if monk.behaviour ~= "down" then monk.desX = nil end | |
377 | monk.behaviour = "down" | |
378 | monk.desX = nil | |
379 | local cmLeft = true | |
380 | local cmRight = true | |
381 | --We try to find the nearest by searching alternate left and right at variable distance | |
382 | for i=1,math.max(monk.x - 1, 49 - monk.x) do | |
383 | if monk.x-i > 0 and cmLeft then | |
384 | --If a wall blocks the monks path, they can't keep going left or right | |
385 | cmLeft = map[monk.y][monk.x-i] ~= 0 | |
386 | --But if it's all clear, they look for something to climb/jump down | |
387 | if cmLeft and (map[monk.y+1][monk.x-i] == "H" or (map[monk.y+1][monk.x-i] == 'h' and goldCount == 0) | |
388 | or map[monk.y+1][monk.x-i] == nil or map[monk.y][monk.x-i] == '-') then | |
389 | monk.desX = monk.x-i | |
390 | break | |
391 | end | |
392 | end | |
393 | if monk.x+i < 50 and cmRight then | |
394 | --If a wall blocks the monks path, they can't keep going left or right | |
395 | cmRight = map[monk.y][monk.x+i] ~= 0 | |
396 | --But if it's all clear, they look for something to climb/jump down | |
397 | if cmRight and (map[monk.y+1][monk.x+i] == "H" or (map[monk.y+1][monk.x+i] == 'h' and goldCount == 0) | |
398 | or map[monk.y+1][monk.x+i] == nil or map[monk.y][monk.x+i] == '-') then | |
399 | monk.desX = monk.x+i | |
400 | break | |
401 | end | |
402 | end | |
403 | end | |
404 | end | |
405 | elseif monk.y > plY then | |
406 | if monk.behaviour ~= "up" then monk.desX = nil end | |
407 | monk.behaviour = "up" | |
408 | --Same deal again- try moving up first | |
409 | if isLegalMove(monk.x,monk.y,monk.x,monk.y-1) then | |
410 | monk.y = monk.y-1 | |
411 | updateMap(monk.x, monk.y+1) | |
412 | drawMonk(monk) | |
413 | monk.desX = nil | |
414 | --You can never move up and start falling, so we don't bother to check | |
415 | --Otherwise they need ladders to climb up | |
416 | elseif monk.desX == nil then | |
417 | monk.behaviour = "up" | |
418 | monk.desX = nil | |
419 | local cmLeft = true | |
420 | local cmRight = true | |
421 | --We try to find the nearest by searching alternate left and right at variable distance | |
422 | for i=1,math.max(monk.x - 1, 49 - monk.x) do | |
423 | if monk.x-i > 0 and cmLeft then | |
424 | --If a wall blocks the monks path or a pit is in the way, they can't keep going left or right | |
425 | cmLeft = map[monk.y][monk.x-i] ~= 0 and (monk.y == #map or map[monk.y+1][monk.x-i] ~= nil | |
426 | or map[monk.y][monk.x-i] == '-') | |
427 | --But if it's all clear, they look for a ladder | |
428 | if cmLeft and (map[monk.y][monk.x-i] == "H" or (map[monk.y][monk.x-i] == 'h' and goldCount == 0)) then | |
429 | monk.desX = monk.x-i | |
430 | break | |
431 | end | |
432 | end | |
433 | if monk.x+i < 50 and cmRight then | |
434 | cmRight = map[monk.y][monk.x+i] ~= 0 and (monk.y == #map or map[monk.y+1][monk.x+i] ~= nil | |
435 | or map[monk.y][monk.x+i] == '-') | |
436 | if cmRight and (map[monk.y][monk.x+i] == "H" or (map[monk.y][monk.x+i] == 'h' and goldCount == 0)) then | |
437 | monk.desX = monk.x+i | |
438 | break | |
439 | end | |
440 | end | |
441 | end | |
442 | end | |
443 | end | |
444 | ||
445 | if not (monk.trapped or monk.dead) then | |
446 | --Has the monk decided on moving left or right? If so we try to move him | |
447 | if monk.desX and not monk.falling then | |
448 | local mdir = monk.desX - monk.x | |
449 | local mdir = mdir / math.abs(mdir) | |
450 | if isLegalMove(monk.x,monk.y,monk.x+mdir,monk.y) then | |
451 | monk.x = monk.x + mdir | |
452 | updateMap(monk.x - mdir, monk.y) | |
453 | drawMonk(monk) | |
454 | else | |
455 | --This allows re-evaluations if they get stuck- not ideal but good enough | |
456 | monk.desX = nil | |
457 | end | |
458 | end | |
459 | monk.falling = (monk.y < #map and map[monk.y][monk.x] ~= '-' and (map[monk.y+1][monk.x] == nil or | |
460 | map[monk.y+1][monk.x] == 2 or map[monk.y+1][monk.x] == '-') and type(map[monk.y][monk.x] ~= "number")) | |
461 | for _,omonk in pairs(monks) do | |
462 | if omonk.x == monk.x and omonk.y == monk.y + 1 then monk.falling = false break end | |
463 | end | |
464 | if monk.x == plX and monk.y == plY + 1 then monk.falling = false end | |
465 | --We have caught and killed the player | |
466 | if monk.x == plX and monk.y == plY and spawnTimer == -1 then | |
467 | spawnTimer = os.startTimer(2) | |
468 | end | |
469 | end | |
470 | end | |
471 | end | |
472 | ||
473 | local function updateBlockTimer(tid) | |
474 | local remAt = nil | |
475 | for i,v in ipairs(blockTimers) do | |
476 | if v.timer == tid then | |
477 | if map[v.y][v.x] == 3 then | |
478 | map[v.y][v.x] = 2 | |
479 | v.timer = os.startTimer(blockIntv) | |
480 | elseif map[v.y][v.x] == 2 then | |
481 | map[v.y][v.x] = 1 | |
482 | v.timer = os.startTimer(0.1) | |
483 | elseif map[v.y][v.x] == 1 then | |
484 | map[v.y][v.x] = 0 | |
485 | --If the player is caught in a block, he dies | |
486 | if v.y == plY and v.x == plX then | |
487 | spawnTimer = os.startTimer(2) | |
488 | end | |
489 | for _,monk in pairs(monks) do | |
490 | if monk.x == v.x and monk.y == v.y then | |
491 | monk.dead = os.startTimer(monkSpawnIntv) | |
492 | --Easiest way to get them out of the way rather than evaluation | |
493 | monk.x = -1 | |
494 | monk.y = -1 | |
495 | monk.trapped = nil | |
496 | end | |
497 | end | |
498 | remAt = i | |
499 | end | |
500 | updateMap(v.x,v.y) | |
501 | break | |
502 | end | |
503 | end | |
504 | if remAt then table.remove(blockTimers,remAt) end | |
505 | end | |
506 | ||
507 | local function shootBlock(x,y) | |
508 | if y <= #map and map[y][x] == 0 and (map[y-1][x] == nil | |
509 | or map[y-1][x] == 2 or (map[y-1][x] == 'h' and goldCount > 0)) then | |
510 | map[y][x] = 3 | |
511 | table.insert(blockTimers, {x = x; y = y; timer = os.startTimer(0.1);} ) | |
512 | updateMap(x,y) | |
513 | end | |
514 | end | |
515 | ||
516 | local function handleEvents() | |
517 | local id,p1,p2,p3 = os.pullEvent() | |
518 | ||
519 | if id == "key" then | |
520 | if p1 == keys.a and moveTimer == -1 and spawnTimer == -1 then | |
521 | movePlayer(plX-1,plY) | |
522 | moveTimer = os.startTimer(moveIntv) | |
523 | elseif p1 == keys.d and moveTimer == -1 and spawnTimer == -1 then | |
524 | movePlayer(plX+1,plY) | |
525 | moveTimer = os.startTimer(moveIntv) | |
526 | elseif p1 == keys.w and moveTimer == -1 and spawnTimer == -1 then | |
527 | movePlayer(plX,plY-1) | |
528 | moveTimer = os.startTimer(moveIntv) | |
529 | elseif p1 == keys.s and moveTimer == -1 and spawnTimer == -1 then | |
530 | movePlayer(plX,plY+1) | |
531 | moveTimer = os.startTimer(moveIntv) | |
532 | elseif p1 == keys.q and shootTimer == -1 and not pfalling and spawnTimer == -1 then | |
533 | shootBlock(plX-1,plY+1) | |
534 | shootTimer = os.startTimer(moveIntv) | |
535 | elseif p1 == keys.e and shootTimer == -1 and not pfalling and spawnTimer == -1 then | |
536 | shootBlock(plX+1,plY+1) | |
537 | shootTimer = os.startTimer(moveIntv) | |
538 | elseif p1 == keys.enter then | |
539 | started = false | |
540 | elseif p1 == keys.t then | |
541 | started = false | |
542 | running = false | |
543 | end | |
544 | elseif id == "timer" then | |
545 | if p1 == shootTimer then shootTimer = -1 | |
546 | elseif p1 == spawnTimer then | |
547 | started = false | |
548 | elseif p1 == moveTimer then | |
549 | if pfalling then | |
550 | movePlayer(plX,plY+1) | |
551 | moveTimer = os.startTimer(moveIntv) | |
552 | else | |
553 | moveTimer = -1 | |
554 | end | |
555 | elseif p1 == monkTimer then | |
556 | updateMonks() | |
557 | monkTimer = os.startTimer(moveIntv * 2) | |
558 | elseif updateBlockTimer(p1) then | |
559 | else | |
560 | for _,monk in pairs(monks) do | |
561 | if p1 == monk.trapped then | |
562 | --You can stand on a monk to force them to be killed- so we check for that | |
563 | --along with being buried in tunnels, etc. | |
564 | local stillTrapped = map[monk.y-1][monk.x] == 0 or (plX == monk.x and plY == monk.y-1) | |
565 | for _,omonk in pairs(monks) do | |
566 | if omonk.x == monk.x and omonk.y == monk.y-1 then | |
567 | stillTrapped = true | |
568 | break | |
569 | end | |
570 | end | |
571 | --Perpetually trapped monks will try to excape much more quickly | |
572 | if stillTrapped then | |
573 | --This needs to be tweaked | |
574 | monk.trapped = os.startTimer(0.75) | |
575 | else | |
576 | --When free, they head in your general direction, re-evaluate later | |
577 | monk.y = monk.y - 1 | |
578 | --This is necessary to stop 'double jumping' | |
579 | monk.desX = nil | |
580 | monk.trapped = nil | |
581 | monk.behaviour = "none" | |
582 | monk.justEscaped = true | |
583 | ||
584 | updateMap(monk.x, monk.y+1) | |
585 | drawMonk(monk) | |
586 | end | |
587 | break | |
588 | elseif p1 == monk.dead then | |
589 | --Same deal- you can camp spawn | |
590 | local stillDead = plX == monk.spawnX and plY == monk.spawnY | |
591 | for _,omonk in pairs(monks) do | |
592 | if omonk.x == monk.spawnX and omonk.y == monk.spawnY then | |
593 | stillDead = true | |
594 | break | |
595 | end | |
596 | end | |
597 | --They'll spawn the second you give them the chance | |
598 | if stillDead then | |
599 | monk.dead = os.startTimer(0.5) | |
600 | else | |
601 | monk.x = monk.spawnX | |
602 | monk.y = monk.spawnY | |
603 | monk.dead = nil | |
604 | monk.justSpawned = true | |
605 | monk.behaviour = "none" | |
606 | drawMonk(monk) | |
607 | break | |
608 | end | |
609 | end | |
610 | end | |
611 | end | |
612 | end | |
613 | end | |
614 | ||
615 | term.clear() | |
616 | if not fs.exists(shell.resolve(".").."/levels") then | |
617 | error("Level directory not present!") | |
618 | end | |
619 | levelList = fs.list(shell.resolve(".").."/levels") | |
620 | if #levelList == 0 then | |
621 | error("Level directory is empty!") | |
622 | end | |
623 | ||
624 | loadMap(shell.resolve(".").."/levels/"..levelList[currentLevel]) | |
625 | while running do | |
626 | drawMap() | |
627 | drawHUD() | |
628 | os.pullEvent("key") | |
629 | monkTimer = os.startTimer(moveIntv * 1.5) | |
630 | ||
631 | started = true | |
632 | while started do | |
633 | handleEvents() | |
634 | end | |
635 | ||
636 | if nextLevel then | |
637 | if currentLevel == #levelList then | |
638 | running = false | |
639 | break | |
640 | else | |
641 | currentLevel = currentLevel + 1 | |
642 | resetMap() | |
643 | loadMap(shell.resolve(".").."/levels/"..levelList[currentLevel]) | |
644 | end | |
645 | nextLevel = false | |
646 | else | |
647 | playerLives = playerLives-1 | |
648 | if playerLives > 0 then resetMap() | |
649 | else running = false end | |
650 | end | |
651 | end | |
652 | ||
653 | if nextLevel then | |
654 | local msg = "All levels defeated, Code Runner!" | |
655 | term.setBackgroundColour(colours.black) | |
656 | term.setTextColour(colours.lime) | |
657 | term.setCursorPos(25 - #msg/2, 2) | |
658 | term.write(msg) | |
659 | else | |
660 | local msg = "Game over!" | |
661 | term.setBackgroundColour(colours.black) | |
662 | term.setTextColour(colours.red) | |
663 | term.setCursorPos(25 - #msg/2, 2) | |
664 | term.write(msg) | |
665 | end | |
666 | sleep(2) | |
667 | term.setCursorPos(19,51) | |
668 | print("") |