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("") |