Advertisement
Guest User

Gold Runner

a guest
Jun 9th, 2013
1,779
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --[[
  2.         Gold Runner
  3.         Inspired by the game by Doug Smith
  4.  
  5.         Written by: Nitrogen Fingers
  6. ]]--
  7. w,h = term.getSize()
  8.  
  9. running = true
  10. started = false
  11. nextLevel = false
  12.  
  13. inLevelSelect = false
  14. inLevelEditor = false
  15. local levelEditName = nil
  16. local hexnums = { [10] = "a", [11] = "b", [12] = "c", [13] = "d", [14] = "e" , [15] = "f" }
  17.  
  18. titleLoaded = false
  19. local menSel = "none"
  20. local titleOptions = { "New Game", "Select Level", "Create Level", "Quit" }
  21. local inGameOptions = { "Restart", "Edit Level", "Back to Title", "Quit" }
  22. local levelEditOptions = { "Save", "Play Level", "Save and Exit", "Discard and Exit" }
  23. local menIndex = 1
  24.  
  25. local maxnamelen = 14
  26.  
  27. local drawOffsetX = 1
  28. local drawOffsetY = 0
  29.  
  30. local map = {}
  31. local goldMap = {}
  32. local blockTimers = {}
  33. local blockIntv = 5
  34.  
  35. local monks = {}
  36. local monkTimer = -1
  37. local monkSpawnIntv = 3
  38. local monkTrapIntv = blockIntv/2
  39.  
  40. local goldCount = 0
  41. local maxGoldCount = 0
  42. local playerLives = 3
  43. local playerScore = 0
  44. local plspawnX = 0
  45. local plspawnY = 0
  46.  
  47. local plX = 0
  48. local plY = 0
  49. local pfalling = false
  50. local moveTimer = -1
  51. local shootTimer = -1
  52. local spawnTimer = -1
  53. local moveIntv = 0.15
  54.  
  55. local exX = 0
  56. local exY = 0
  57.  
  58. local levelList = {}
  59. local currentLevel = 1
  60. local levelLot = 1
  61.  
  62. local titleLevel = {
  63.     "                                                 ";
  64.     "                                  dddddddddddc   ";
  65.     "                                 4           c   ";
  66.     "      4                                    4 c   ";
  67.     "  bbbbbbc                               bcbbbb   ";
  68.     "  b 4 b c                                c       ";
  69.     "  bbbbb c  4                  dd 0     4 c 4     ";
  70.     "        bbcb                    bbb     bbbbc    ";
  71.     "          c                                 c    ";
  72.     "          c                             ddd c  eb";
  73.     "     dddddc                          bcb   cbbbbb";
  74.     "    c                                 c    c bbbb";
  75.     "b4  c                                4c     bb44b";
  76.     "bbb c    4  e                   bbbcbbbbbbbbbbbbb";
  77.     "bbbbbbbbbbbbbbc           4        cbbbbb 4  bbbb";
  78.     "bbbbbbfff44fbbc 4     cbbbbbbb     cbbbbbbb bbbbb";
  79.     "bbbbffffbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 4 bbbbbbb";
  80.     "bbbffbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb5  bbbbbbbbb";
  81. }
  82.  
  83. local function parseValue(x, y, lchar)
  84. if tonumber(lchar, 16) then
  85.     lchar = math.pow(2, tonumber(lchar,16))
  86.    
  87.     if lchar == colours.blue then
  88.       map[y][x] = 0
  89.     elseif lchar == colours.brown then
  90.       map[y][x] = 'H'
  91.     elseif lchar == colours.yellow then
  92.       goldMap[y][x] = 1
  93.       goldCount = goldCount + 1
  94.     elseif lchar == colours.orange then
  95.       map[y][x] = 'V'
  96.     elseif lchar == colours.green then
  97.       map[y][x] = '-'
  98.     elseif lchar == colours.lightGrey then
  99.       map[y][x] = 'h'
  100.     elseif lchar == colours.grey then
  101.       map[y][x] = '#'
  102.     elseif lchar == colours.white then
  103.       plX = x
  104.       plspawnX = x
  105.       plY = y
  106.       plspawnY = y
  107.     elseif lchar == colours.lime then
  108.       exX = x
  109.       exY = y
  110.     elseif lchar == colours.red then
  111.       table.insert(monks, {
  112.         --X and Y, clear enough
  113.         x = x, y = y;
  114.         --Where they spawn when they die
  115.         spawnX = x, spawnY = y;
  116.         -- Any gold they're carring- it's a 1 in 5
  117.         gold = false;
  118.         -- Whether or not they're falling
  119.         falling = false;
  120.         -- Timer if they're dead to respawn
  121.         dead = nil;
  122.         --Whether or not the monk has just spawned
  123.         justSpawned = true;
  124.         --Whether or not the monk has just escaped
  125.         justEscaped = false;
  126.         -- Current aim- it's "up", "down", "across" or "none"
  127.         behaviour = "none";
  128.         -- The desired x position to travel to, when one is necessary.
  129.         desX = nil;
  130.         -- The escape timer
  131.         trapped = nil;
  132.       })
  133.     end
  134.   end
  135. end
  136.  
  137. local function loadMap(_sPath)
  138.   if not fs.exists(_sPath) then return false end
  139.   map = {}
  140.   goldMap = {}
  141.   monks = {}
  142.   goldCount = 0
  143.    
  144.   local file = fs.open(_sPath, "r")
  145.   local line = file:readLine()
  146.   while line do
  147.     goldMap[#map+1] = {}
  148.     map[#map+1] = {}
  149.     for i=1,math.min(#line,49) do
  150.       local lchar = string.sub(line,i,i)
  151.       parseValue(i, #map, lchar)
  152.     end
  153.     if #map == 18 then break end
  154.     line = file:readLine()
  155.   end
  156.   file:close()
  157.   maxGoldCount = goldCount
  158.   titleLoaded = false
  159.   return true
  160. end
  161.  
  162. --When something moves or something needs to be drawn, we
  163. --just change the appropriate tile with this method.
  164. local function updateMap(x,y)
  165.     term.setCursorPos(x + drawOffsetX, y + drawOffsetY)
  166.     term.setBackgroundColour(colours.black)
  167.     if plX == x and plY == y and map[y][x] ~= 0 then
  168.       term.setTextColour(colours.white)
  169.       if map[y][x] == 1 then term.setBackgroundColour(colours.lightBlue)
  170.       elseif map[y][x] == "V" then term.setBackgroundColour(colours.blue) end
  171.       term.write("&")
  172.     elseif map[y][x] == 'H' then
  173.       term.setTextColour(colours.brown)
  174.       term.write("H")
  175.     --Level Editor stuff
  176.     elseif map[y][x] == 'h' and (goldCount == 0 or inLevelEditor) then
  177.       if inLevelEditor then term.setTextColour(colours.lightGrey)
  178.       else term.setTextColour(colours.brown) end
  179.       term.write("H")
  180.     elseif map[y][x] == '&' and inLevelEditor then
  181.       term.setTextColour(colours.pink)
  182.       term.write('&')
  183.     elseif map[y][x] == 'V' then
  184.       term.setBackgroundColour(colours.blue)
  185.       if inLevelEditor then
  186.         term.setTextColour(colours.orange)
  187.         term.write("V")
  188.       else
  189.         term.write(" ")
  190.       end
  191.     elseif map[y][x] == '-' then
  192.       term.setTextColour(colours.brown)
  193.       term.write(map[y][x])
  194.     elseif map[y][x] == '#' then
  195.       term.setBackgroundColour(colours.grey)
  196.       term.write(" ")
  197.     elseif type(map[y][x]) == "number" then
  198.       local uchar = ' '
  199.       if map[y][x] == 3 then
  200.         term.setBackgroundColour(colours.lightBlue)
  201.       elseif map[y][x] == 2 and goldMap[y][x] == 1 then
  202.         term.setTextColour(colours.yellow)
  203.         uchar = '$'
  204.       elseif map[y][x] == 1 then
  205.         term.setBackgroundColour(colours.lightBlue)
  206.       elseif map[y][x] == 0 then
  207.         term.setBackgroundColour(colours.blue)
  208.       end
  209.       term.write(uchar)
  210.     elseif goldMap[y][x] == 1 then
  211.       term.setTextColour(colours.yellow)
  212.       term.write("$")
  213.     elseif exX == x and exY == y and (goldCount == 0 or inLevelEditor) then
  214.       term.setTextColour(colours.lime)
  215.       term.write("@")
  216.     else
  217.       term.write(" ")
  218.     end
  219. end
  220.  
  221. --It's silly to iterate through all monks when drawing tiles, so
  222. --we do it separately.
  223. local function drawMonk(monk)
  224.     term.setCursorPos(monk.x + drawOffsetX, monk.y + drawOffsetY)
  225.     if monk.justSpawned then term.setTextColour(colours.pink)
  226.     else term.setTextColour(colours.red) end
  227.     if map[monk.y][monk.x] == 1 then term.setBackgroundColour(colours.lightBlue)
  228.     elseif map[monk.y][monk.x] == "V" then term.setBackgroundColour(colours.blue)
  229.     else term.setBackgroundColour(colours.black) end
  230.     term.write("&")
  231. end
  232.  
  233. --Draws the map for the first time. It barely changes, so we really
  234. --only call this the once.
  235. local function drawMap()
  236.   term.setBackgroundColour(colours.black)
  237.   term.clear()
  238.   for y=1,#map do
  239.     for x=1,49 do
  240.       updateMap(x,y)
  241.     end
  242.   end
  243.   for _,monk in pairs(monks) do drawMonk(monk)end
  244. end
  245.  
  246. --When all coins have been collected, we add in invisble ladders and
  247. --the end game portal.
  248. local function drawEndgameMap()
  249.   for y=1,#map do
  250.     for x=1,49 do
  251.       if map[y][x] == 'h' or (exX == x and exY == y) then
  252.         updateMap(x,y)
  253.       end
  254.     end
  255.   end
  256. end
  257.  
  258. --Sets the map back to defaults, so we can start afresh
  259. local function resetMap()
  260.     goldCount = maxGoldCount
  261.     for i=1,#goldMap do
  262.         for j=1,49 do
  263.             if goldMap[i][j] == 0 then goldMap[i][j] = 1 end
  264.         end
  265.     end
  266.     for _,monk in pairs(monks) do
  267.         monk.justSpawned = true
  268.         monk.dead = nil
  269.         monk.trapped = nil
  270.         monk.justEscaped = false
  271.         monk.falling = false
  272.         monk.behaviour = "none"
  273.         monk.x = monk.spawnX
  274.         monk.y = monk.spawnY
  275.     end
  276.    
  277.     for _,timer in pairs(blockTimers) do
  278.         map[timer.y][timer.x] = 0
  279.     end
  280.     blockTimers = {}
  281.     plX = plspawnX
  282.     plY = plspawnY
  283.    
  284.     moveTimer = -1
  285.     shootTimer = -1
  286.     spawnTimer = -1
  287.     monkTimer = -1
  288.     pfalling = false
  289. end
  290.  
  291. --Draws the HUD. This also rarely changes, so we update it when something happens.
  292. local function drawHUD()
  293.   term.setCursorPos(2,19)
  294.   term.setBackgroundColour(colours.black)
  295.   term.clearLine()
  296.   term.setTextColour(colours.blue)
  297.   term.write("Score: ")
  298.   term.setTextColour(colours.yellow)
  299.   term.write(string.rep("0", 5-math.floor(math.log10(playerScore + 1)))
  300.     ..playerScore)
  301.   term.setTextColour(colours.yellow)
  302.   term.setCursorPos(25 - #levelList[currentLevel]/2, 19)
  303.   term.write(levelList[currentLevel])
  304.   local lstr = "Men: "
  305.   term.setCursorPos(50 - #lstr - math.floor(math.log10(playerLives)), 19)
  306.   term.setTextColour(colours.blue)
  307.   term.write(lstr)
  308.   term.setTextColour(colours.yellow)
  309.   term.write(playerLives.."")
  310. end
  311.  
  312. --Draws the list of levels known, with respect to screen
  313. --real estate
  314. local function drawLevelList()
  315.     local minLev = ((levelLot-1) * 10 + 1)
  316.     local maxLev = minLev + math.min(10, #levelList - (levelLot-1) * 10) - 1
  317.    
  318.     term.setCursorPos(7, 2)
  319.     term.setBackgroundColour(colours.black)
  320.     term.clearLine()
  321.     for j = 1,49 do updateMap(j,2) end
  322.    
  323.     term.setBackgroundColour(colours.black)
  324.     term.setTextColour(colours.white)
  325.     term.setCursorPos(7, 2)
  326.     local msg = "Levels "..minLev.." to "..maxLev.." of "..#levelList
  327.     term.write(msg)
  328.    
  329.     term.setTextColour(colours.yellow)
  330.     term.setCursorPos(4, 2)
  331.     if levelLot > 1 then term.write("<-")
  332.     else term.write("  ") end
  333.    
  334.     term.setCursorPos(8 + #msg, 2)
  335.     if maxLev < #levelList then term.write("->")
  336.     else term.write(" ") end
  337.    
  338.     for i = 1,10 do
  339.         term.setCursorPos(1, 3+i)
  340.         for j = 1,49 do updateMap(j,3+i) end
  341.         term.setTextColour(colours.white)
  342.         term.setBackgroundColour(colours.black)
  343.         term.setCursorPos(17, 3+i)
  344.         if i + (levelLot-1)*10 - 1 < maxLev then
  345.             term.write(levelList[10 * (levelLot-1) + i])
  346.         end
  347.     end
  348. end
  349.  
  350. --Loads up and draws up the title screen, for a nice
  351. --intro to Gold Runner
  352. local function loadTitleScreen()
  353.   map = {}
  354.   goldMap = {}
  355.   monks = {}
  356.   goldCount = 0
  357.   for i=1,#titleLevel do
  358.     local line = titleLevel[i]
  359.     goldMap[#map+1] = {}
  360.     map[#map+1] = {}
  361.     for i=1,math.min(#line,49) do
  362.       local lchar = string.sub(line,i,i)
  363.       parseValue(i, #map, lchar)
  364.     end
  365.     if #map == 18 then break end
  366.   end
  367.   maxGoldCount = goldCount
  368.  
  369.   drawMap()
  370.   term.setCursorPos(1,19)
  371.   term.setBackgroundColour(colours.blue)
  372.   term.clearLine()
  373.  
  374.   menIndex = 1
  375.   titleLoaded = true
  376. end
  377.  
  378. --Opens an in-game menu to display a series of options.
  379. local function inGameMenu(menuList)
  380.     menIndex = 1
  381.    
  382.     local squareTop,squareBottom = 4,6 + #menuList * 2
  383.     local squareSize = 0
  384.     for i=1,#menuList do squareSize = math.max(squareSize, #menuList[i] + 6) end
  385.    
  386.     for y=squareTop,squareBottom do
  387.         term.setCursorPos(w/2 - squareSize/2, y)
  388.         term.setBackgroundColour(colours.lightBlue)
  389.         term.write(string.rep(" ", squareSize))
  390.        
  391.         if y ~= squareTop and y ~= squareBottom then
  392.             term.setCursorPos(w/2 - squareSize/2 + 1, y)
  393.             term.setBackgroundColour(colours.black)
  394.             term.write(string.rep(" ", squareSize - 2))
  395.         end
  396.        
  397.         if y ~= squareTop and y ~= squareBottom and y % 2 == 0 then
  398.             local opt = menuList[(y - squareTop) / 2]
  399.             term.setCursorPos(w/2 - #opt/2, y)
  400.             term.setTextColour(colours.white)
  401.             term.write(opt)
  402.         end
  403.     end
  404.    
  405.     local p1 = nil
  406.     repeat
  407.         for i=1,#menuList do
  408.             term.setBackgroundColour(colours.black)
  409.             term.setTextColour(colours.yellow)
  410.             if i == menIndex then
  411.                 term.setCursorPos(w/2 - squareSize/2 + 1, squareTop + i * 2)
  412.                 term.write(">")
  413.                 term.setCursorPos(w/2 + squareSize/2 - 2, squareTop + i * 2)
  414.                 term.write("<")
  415.             else
  416.                 term.setCursorPos(w/2 - squareSize/2 + 1, squareTop + i * 2)
  417.                 term.write(" ")
  418.                 term.setCursorPos(w/2 + squareSize/2 - 2, squareTop + i * 2)
  419.                 term.write(" ")
  420.             end
  421.         end
  422.         _,p1 = os.pullEvent("key")
  423.        
  424.         if p1 == keys.up and menIndex > 1 then menIndex = menIndex - 1
  425.         elseif p1 == keys.down and menIndex < #menuList then menIndex = menIndex + 1 end
  426.     until p1 == keys.enter
  427.    
  428.     return menuList[menIndex]
  429. end
  430.  
  431. --Checks to see if any given desired move is legal. Monks and players both use this.
  432. local function isLegalMove(initX,initY,finX,finY)
  433.     if finY < 1 or finY > #map or finX < 1 or finX > 49 then
  434.         return false
  435.     end
  436.    
  437.     if map[finY][finX] ~= 0 and map[finY][finX] ~= '#' then
  438.         --This reports 'self moves' as being illegal, but that's fine
  439.         for _,monk in pairs(monks) do
  440.             if monk.x == finX and monk.y == finY then return false end
  441.         end
  442.  
  443.         if finY == initY-1 and (map[initY][initX] == "H" or (map[initY][initX] == "h" and goldCount == 0))
  444.             then return true
  445.         elseif finY == initY+1 and (map[finY][finX] == "H" or (map[finY][finX] == "h" and goldCount == 0)
  446.                 or (type(map[finY][finX]) == "number" and map[finY][finX] > 0) or map[finY][finX] == nil or
  447.                 map[finY][finX] == "V" or map[finY][finX] == "-" or (map[finY][finX] == 'h' and goldCount ~= 0))
  448.             then return true
  449.         elseif finX == initX-1 or finX == initX+1 then
  450.             return true
  451.         end
  452.     end
  453. end
  454.  
  455. --Moves the player to a given step.
  456. local function movePlayer(x,y,ignoreLegal)
  457.     if not ignoreLegal and not isLegalMove(plX,plY,x,y) then return false end
  458.    
  459.     local ox = plX
  460.     local oy = plY
  461.     plX = x
  462.     plY = y
  463.    
  464.     updateMap(ox,oy)
  465.     updateMap(x,y)
  466.     if goldMap[y][x] == 1 then
  467.         goldMap[y][x] = 0
  468.         goldCount = goldCount - 1
  469.         playerScore = playerScore + 5
  470.         if started then drawHUD() end
  471.         if (goldCount == 0) then
  472.             drawEndgameMap()
  473.         end
  474.     elseif exX == plX and exY == plY and goldCount == 0 then
  475.         started = false
  476.         nextLevel = true
  477.     end
  478.    
  479.     pfalling = (y < #map and map[y][x] ~= '-' and map[y][x] ~= 'H' and not (map[y][x] == 'h' and goldCount == 0)
  480.         and (map[y+1][x] == nil or map[y+1][x] == "V" or map[y+1][x] == 2 or map[y+1][x] == '-'))
  481.     if (y < #map and map[y+1][x] == 'h' and goldCount ~= 0) then pfalling = true end
  482.     for _,monk in pairs(monks) do
  483.         if monk.x == plX and monk.y == plY + 1 then pfalling = false break end
  484.     end
  485.    
  486.     return true
  487. end
  488.  
  489. local function updateMonks()
  490.     for _,monk in pairs(monks) do
  491.         --Absolute first step- if he's trapped or dead, he's going nowhere
  492.         if monk.trapped or monk.dead then
  493.         --If he's just spawned he takes a second to orient himself
  494.         elseif monk.justSpawned then
  495.             monk.justSpawned = false
  496.             --We evaluate their falling behaviour here (as freed monks CAN stand on air)
  497.             monk.falling = (monk.y < #map and map[monk.y][monk.x] ~= '-' and map[monk.y][monk.x] ~= "H" and not
  498.                     (map[monk.y][monk.x] == 'h' and goldCount == 0) and (map[monk.y+1][monk.x] == nil or map[monk.y+1][monk.x] == "V" or
  499.                     map[monk.y+1][monk.x] == 2 or map[monk.y+1][monk.x] == '-') and type(map[monk.y][monk.x] ~= "number"))
  500.             for _,omonk in pairs(monks) do
  501.                 if omonk.x == monk.x and omonk.y == monk.y + 1 then monk.falling = false break end
  502.             end
  503.             if monk.x == plX and monk.y == plY + 1 then monk.falling = false end
  504.         --Then we consider if he's just gotten out of a hole
  505.         elseif monk.justEscaped then
  506.             monk.justEscaped = false
  507.             --He tries the player side first
  508.             local playerSide = (plX-monk.x) / math.abs(plX-monk.x)
  509.             if isLegalMove(monk.x, monk.y, monk.x + playerSide, monk.y) then
  510.                 monk.x = monk.x + playerSide
  511.                 updateMap(monk.x - playerSide, monk.y)
  512.             elseif isLegalMove(monk.x, monk.y, monk.x - playerSide, monk.y) then
  513.                 monk.x = monk.x - playerSide
  514.                 updateMap(monk.x + playerSide, monk.y)
  515.             end
  516.             drawMonk(monk)
  517.         --Then we evaluate falling
  518.         elseif monk.falling then
  519.             monk.behaviour = "none"
  520.             monk.y = monk.y + 1
  521.             updateMap(monk.x, monk.y-1)
  522.             drawMonk(monk)
  523.             monk.desX = nil
  524.             if type(map[monk.y][monk.x]) == "number" then
  525.                 monk.trapped = os.startTimer(monkTrapIntv)
  526.                 monk.falling = false
  527.             else
  528.                 monk.falling = (monk.y < #map and map[monk.y][monk.x] ~= '-' and map[monk.y][monk.x] ~= "H" and not
  529.                     (map[monk.y][monk.x] == 'h' and goldCount == 0) and (map[monk.y+1][monk.x] == nil or map[monk.y+1][monk.x] == "V" or
  530.                     map[monk.y+1][monk.x] == 2 or map[monk.y+1][monk.x] == '-') and type(map[monk.y][monk.x] ~= "number"))
  531.                 for _,omonk in pairs(monks) do
  532.                     if omonk.x == monk.x and omonk.y == monk.y + 1 then monk.falling = false break end
  533.                 end
  534.                 if monk.x == plX and monk.y == plY + 1 then monk.falling = false end
  535.                 if monk.justEscaped then monk.falling = false end
  536.             end
  537.         --If he's on his feet and not trapped, he's allowed to think about where to move
  538.         elseif monk.y == plY then
  539.             --Is the monk on the same level as the player? How lucky! They'll just walk towards him
  540.             monk.desX = plX
  541.             monk.behaviour = "across"
  542.         --Y difference takes precedence over X (as in the original, makes them a bit smarter)
  543.         elseif monk.y < plY then
  544.             --If they can move up, they will
  545.             if isLegalMove(monk.x,monk.y,monk.x,monk.y+1) and not monk.justEscaped then
  546.                 monk.y = monk.y+1
  547.                 updateMap(monk.x, monk.y-1)
  548.                 drawMonk(monk)
  549.                 monk.desX = nil
  550.                 --A down move can lead to a fall, so we check if they're now falling.
  551.                 monk.falling = (monk.y < #map and map[monk.y][monk.x] ~= '-' and map[monk.y][monk.x] ~= "H" and not
  552.                     (map[monk.y][monk.x] == 'h' and goldCount == 0) and (map[monk.y+1][monk.x] == nil or map[monk.y+1][monk.x] == "V" or
  553.                     map[monk.y+1][monk.x] == 2 or map[monk.y+1][monk.x] == '-') and type(map[monk.y][monk.x] ~= "number"))
  554.                 for _,omonk in pairs(monks) do
  555.                     if omonk.x == monk.x and omonk.y == monk.y + 1 then monk.falling = false break end
  556.                 end
  557.                 if monk.x == plX and monk.y == plY + 1 then monk.falling = false end
  558.             --Otherwise, it's off to the nearest ladder, monkey bars or perilous ledge to jump off
  559.             --assuming they haven't found one already
  560.             elseif monk.desX == nil then
  561.                 if monk.behaviour ~= "down" then monk.desX = nil end
  562.                 monk.behaviour = "down"
  563.                 monk.desX = nil
  564.                 local cmLeft = true
  565.                 local cmRight = true
  566.                 --We try to find the nearest by searching alternate left and right at variable distance
  567.                 for i=1,math.max(monk.x - 1, 49 - monk.x) do
  568.                     if monk.x-i > 0 and cmLeft then
  569.                         --If a wall blocks the monks path, they can't keep going left or right
  570.                         cmLeft = map[monk.y][monk.x-i] ~= 0
  571.                         --But if it's all clear, they look for something to climb/jump down
  572.                         if cmLeft and (map[monk.y+1][monk.x-i] == "H" or (map[monk.y+1][monk.x-i] == 'h' and goldCount == 0)
  573.                             or map[monk.y+1][monk.x-i] == nil or map[monk.y][monk.x-i] == '-') then
  574.                             monk.desX = monk.x-i
  575.                             break
  576.                         end
  577.                     end
  578.                     if monk.x+i < 50 and cmRight then
  579.                         --If a wall blocks the monks path, they can't keep going left or right
  580.                         cmRight = map[monk.y][monk.x+i] ~= 0
  581.                         --But if it's all clear, they look for something to climb/jump down
  582.                         if cmRight and (map[monk.y+1][monk.x+i] == "H" or (map[monk.y+1][monk.x+i] == 'h' and goldCount == 0)
  583.                             or map[monk.y+1][monk.x+i] == nil or map[monk.y][monk.x+i] == '-') then
  584.                             monk.desX = monk.x+i
  585.                             break
  586.                         end
  587.                     end
  588.                 end
  589.             end
  590.         elseif monk.y > plY then
  591.             if monk.behaviour ~= "up" then monk.desX = nil end
  592.             monk.behaviour = "up"
  593.             --Same deal again- try moving up first
  594.             if isLegalMove(monk.x,monk.y,monk.x,monk.y-1) then
  595.                 monk.y = monk.y-1
  596.                 updateMap(monk.x, monk.y+1)
  597.                 drawMonk(monk)
  598.                 monk.desX = nil
  599.                 --You can never move up and start falling, so we don't bother to check
  600.             --Otherwise they need ladders to climb up
  601.             elseif monk.desX == nil then
  602.                 monk.behaviour = "up"
  603.                 monk.desX = nil
  604.                 local cmLeft = true
  605.                 local cmRight = true
  606.                 --We try to find the nearest by searching alternate left and right at variable distance
  607.                 for i=1,math.max(monk.x - 1, 49 - monk.x) do
  608.                     if monk.x-i > 0 and cmLeft then
  609.                         --If a wall blocks the monks path or a pit is in the way, they can't keep going left or right
  610.                         cmLeft = map[monk.y][monk.x-i] ~= 0 and (monk.y == #map or map[monk.y+1][monk.x-i] ~= nil
  611.                                 or map[monk.y][monk.x-i] == '-' or map[monk.y][monk.x-i] == "H" or (map[monk.y][monk.x-i] == "h"
  612.                                 and goldCount == 0))
  613.                         --But if it's all clear, they look for a ladder
  614.                         if cmLeft and (map[monk.y][monk.x-i] == "H" or (map[monk.y][monk.x-i] == 'h' and goldCount == 0)) then
  615.                             monk.desX = monk.x-i
  616.                             break
  617.                         end
  618.                     end
  619.                     if monk.x+i < 50 and cmRight then
  620.                         cmRight = map[monk.y][monk.x+i] ~= 0 and (monk.y == #map or map[monk.y+1][monk.x+i] ~= nil
  621.                                 or map[monk.y][monk.x+i] == '-' or map[monk.y][monk.x+i] == "H" or (map[monk.y][monk.x+i] == "h"
  622.                                 and goldCount == 0))
  623.                         if cmRight and (map[monk.y][monk.x+i] == "H" or (map[monk.y][monk.x+i] == 'h' and goldCount == 0)) then
  624.                             monk.desX = monk.x+i
  625.                             break
  626.                         end
  627.                     end
  628.                 end
  629.             end
  630.         end
  631.        
  632.         if not (monk.trapped or monk.dead) then
  633.             --Has the monk decided on moving left or right? If so we try to move him
  634.             if monk.desX and not monk.falling then
  635.                 local mdir = monk.desX - monk.x
  636.                 local mdir = mdir / math.abs(mdir)
  637.                 if isLegalMove(monk.x,monk.y,monk.x+mdir,monk.y) then
  638.                     monk.x = monk.x + mdir
  639.                     updateMap(monk.x - mdir, monk.y)
  640.                     drawMonk(monk)
  641.                 else
  642.                     --This allows re-evaluations if they get stuck- not ideal but good enough
  643.                     monk.desX = nil
  644.                 end
  645.             end
  646.             monk.falling = (monk.y < #map and map[monk.y][monk.x] ~= '-' and map[monk.y][monk.x] ~= "H" and not
  647.                     (map[monk.y][monk.x] == 'h' and goldCount == 0) and (map[monk.y+1][monk.x] == nil or map[monk.y+1][monk.x] == "V" or
  648.                     map[monk.y+1][monk.x] == 2 or map[monk.y+1][monk.x] == '-') and type(map[monk.y][monk.x] ~= "number"))
  649.             for _,omonk in pairs(monks) do
  650.                 if omonk.x == monk.x and omonk.y == monk.y + 1 then monk.falling = false break end
  651.             end
  652.             if monk.x == plX and monk.y == plY + 1 then monk.falling = false end
  653.             --We have caught and killed the player
  654.             if monk.x == plX and monk.y == plY and spawnTimer == -1 then
  655.                 spawnTimer = os.startTimer(2)
  656.             end
  657.         end
  658.     end
  659. end
  660.  
  661. local function updateBlockTimer(tid)
  662.     local remAt = nil
  663.     for i,v in ipairs(blockTimers) do
  664.         if v.timer == tid then
  665.             if map[v.y][v.x] == 3 then
  666.                 for _,monk in pairs(monks) do
  667.                     if monk.x == v.x and monk.y == v.y-1 then
  668.                         map[v.y][v.x] = 0
  669.                         remAt = i
  670.                         break
  671.                     end
  672.                 end
  673.                 if not remAt then
  674.                     map[v.y][v.x] = 2
  675.                     v.timer = os.startTimer(blockIntv)
  676.                 end
  677.             elseif map[v.y][v.x] == 2 then
  678.                 map[v.y][v.x] = 1
  679.                 v.timer = os.startTimer(0.1)
  680.             elseif map[v.y][v.x] == 1 then
  681.                 map[v.y][v.x] = 0
  682.                 --If the player is caught in a block, he dies
  683.                 if v.y == plY and v.x == plX then
  684.                     spawnTimer = os.startTimer(2)
  685.                 end
  686.                 for _,monk in pairs(monks) do
  687.                     if monk.x == v.x and monk.y == v.y then
  688.                         monk.dead = os.startTimer(monkSpawnIntv)
  689.                         --Easiest way to get them out of the way rather than evaluation
  690.                         monk.x = -1
  691.                         monk.y = -1
  692.                         monk.trapped = nil
  693.                     end
  694.                 end
  695.                 remAt = i
  696.             end
  697.             updateMap(v.x,v.y)
  698.             break
  699.         end
  700.     end
  701.     if remAt then table.remove(blockTimers,remAt) end
  702. end
  703.  
  704. local function shootBlock(x,y)
  705.     if y <= #map and map[y][x] == 0 and (map[y-1][x] == nil
  706.             or map[y-1][x] == 2 or (map[y-1][x] == 'h' and goldCount > 0)) then
  707.         map[y][x] = 3
  708.         table.insert(blockTimers, {x = x; y = y; timer = os.startTimer(0.1);} )
  709.         updateMap(x,y)
  710.     end
  711. end
  712.  
  713. local function handleEvents()
  714.     local id,p1,p2,p3 = os.pullEvent()
  715.    
  716.     if id == "key" then
  717.         --Menu Handling
  718.         if p1 == keys.up then
  719.             if menIndex > 1 then menIndex = menIndex - 1 end
  720.         elseif p1 == keys.down then
  721.             if inLevelSelect then
  722.                 if menIndex < math.min(10, #levelList - (levelLot-1)*10) then
  723.                     menIndex = menIndex + 1
  724.                 end
  725.             elseif menIndex < #titleOptions then menIndex = menIndex + 1 end
  726.         elseif p1 == keys.left and inLevelSelect and levelLot > 1 then
  727.             levelLot = levelLot - 1
  728.             drawLevelList()
  729.         elseif p1 == keys.right and inLevelSelect and levelLot * 10 < #levelList then
  730.             levelLot = levelLot + 1
  731.             drawLevelList()
  732.         end
  733.    
  734.         --Game Handling
  735.         if p1 == keys.a and moveTimer == -1 and spawnTimer == -1 then
  736.             movePlayer(plX-1,plY)
  737.             moveTimer = os.startTimer(moveIntv)
  738.         elseif p1 == keys.d and moveTimer == -1 and spawnTimer == -1 then
  739.             movePlayer(plX+1,plY)
  740.             moveTimer = os.startTimer(moveIntv)
  741.         elseif p1 == keys.w and moveTimer == -1 and spawnTimer == -1 then
  742.             movePlayer(plX,plY-1)
  743.             moveTimer = os.startTimer(moveIntv)
  744.         elseif p1 == keys.s and moveTimer == -1 and spawnTimer == -1 then
  745.             movePlayer(plX,plY+1)
  746.             moveTimer = os.startTimer(moveIntv)
  747.         elseif p1 == keys.q and shootTimer == -1 and not pfalling and spawnTimer == -1 then
  748.             shootBlock(plX-1,plY+1)
  749.             shootTimer = os.startTimer(moveIntv)
  750.         elseif p1 == keys.e and shootTimer == -1 and not pfalling and spawnTimer == -1 then
  751.             shootBlock(plX+1,plY+1)
  752.             shootTimer = os.startTimer(moveIntv)
  753.         elseif p1 == keys.space and started then
  754.             started = false
  755.         elseif p1 == keys.enter then
  756.             if not started then
  757.                 if inLevelSelect then
  758.                     currentLevel = menIndex + (levelLot - 1) * 10
  759.                     menSel = "New Game"
  760.                 else
  761.                     menSel = titleOptions[menIndex]
  762.                 end
  763.             else
  764.                 started = false
  765.                 menIndex = 1
  766.                 menSel = inGameMenu(inGameOptions)
  767.             end
  768.         end
  769.     elseif id == "timer" then
  770.         if p1 == shootTimer then shootTimer = -1
  771.         elseif p1 == spawnTimer then
  772.             started = false
  773.         elseif p1 == moveTimer then
  774.             if pfalling then
  775.                 movePlayer(plX,plY+1)
  776.                 moveTimer = os.startTimer(moveIntv)
  777.             else
  778.                 moveTimer = -1
  779.             end
  780.         elseif p1 == monkTimer then
  781.             updateMonks()
  782.             monkTimer = os.startTimer(moveIntv * 2)
  783.         elseif updateBlockTimer(p1) then
  784.         else
  785.             for _,monk in pairs(monks) do
  786.                 if p1 == monk.trapped then
  787.                     --You can stand on a monk to force them to be killed- so we check for that
  788.                     --along with being buried in tunnels, etc.
  789.                     local stillTrapped = map[monk.y-1][monk.x] == 0 or (plX == monk.x and plY == monk.y-1)
  790.                     for _,omonk in pairs(monks) do
  791.                         if omonk.x == monk.x and omonk.y == monk.y-1 then
  792.                             stillTrapped = true
  793.                             break
  794.                         end
  795.                     end
  796.                     --Perpetually trapped monks will try to excape much more quickly
  797.                     if stillTrapped then
  798.                         --This needs to be tweaked
  799.                         monk.trapped = os.startTimer(0.75)
  800.                     else
  801.                         --When free, they head in your general direction, re-evaluate later
  802.                         monk.y = monk.y - 1
  803.                         --This is necessary to stop 'double jumping'
  804.                         monk.desX = nil
  805.                         monk.trapped = nil
  806.                         monk.behaviour = "none"
  807.                         monk.justEscaped = true
  808.                        
  809.                         updateMap(monk.x, monk.y+1)
  810.                         drawMonk(monk)
  811.                     end
  812.                     break
  813.                 elseif p1 == monk.dead then
  814.                     --Same deal- you can camp spawn
  815.                     local stillDead = plX == monk.spawnX and plY == monk.spawnY
  816.                     for _,omonk in pairs(monks) do
  817.                         if omonk.x == monk.spawnX and omonk.y == monk.spawnY then
  818.                             stillDead = true
  819.                             break
  820.                         end
  821.                     end
  822.                     --They'll spawn the second you give them the chance
  823.                     if stillDead then
  824.                         monk.dead = os.startTimer(0.5)
  825.                     else
  826.                         monk.x = monk.spawnX
  827.                         monk.y = monk.spawnY
  828.                         monk.dead = nil
  829.                         monk.justSpawned = true
  830.                         monk.behaviour = "none"
  831.                         drawMonk(monk)
  832.                         break
  833.                     end
  834.                 end
  835.             end
  836.         end
  837.     end
  838. end
  839.  
  840. --[[            Level Editor            ]]--
  841.  
  842. local pallette = {  { t = colours.black, b = colours.blue, s = " ", n = "Solid Ground", v = 0 },
  843.                     { t = colours.orange, b = colours.blue, s = "V", n = "Trap Ground", v = "V" },
  844.                     { t = colours.grey, b = colours.grey, s = " ", n = "Cement Ground", v = "#" },
  845.                     { t = colours.brown, b = colours.black, s = "H", n = "Ladder", v = "H" },
  846.                     { t = colours.brown, b = colours.black, s = "-", n = "Monkey Bars", v = "-" },
  847.                     { t = colours.white, b = colours.black, s = "&", n = "Player Spawn", v = "player" },
  848.                     { t = colours.red, b = colours.black, s = "&", n = "Mad Monk", v = "&" },
  849.                     { t = colours.yellow, b = colours.black, s = "$", n = "Gold", v = "$" },
  850.                     { t = colours.lightGrey, b = colours.black, s = "H", n = "Hidden Ladder", v = "h" },
  851.                     { t = colours.lime, b = colours.black, s = "@", n = "Exit Portal", v = "@" },
  852.                     { t = colours.red, b = colours.black, s = "ERASE", n = "Eraser", v = nil } }
  853. local brushType = 1
  854.  
  855. local function getHexOf(colour)
  856.     if not colour or not tonumber(colour) then
  857.         return " "
  858.     end
  859.     local value = math.log(colour)/math.log(2)
  860.     if value > 9 then
  861.         value = hexnums[value]
  862.     end
  863.     return value
  864. end
  865.  
  866. local function drawFooter()
  867.     for i=1,h-1 do
  868.         if i % 2 == 0 then term.setBackgroundColour(colours.grey)
  869.         else term.setBackgroundColour(colours.yellow) end
  870.         term.setCursorPos(1,i)
  871.         term.write(" ")
  872.         term.setCursorPos(w,i)
  873.         term.write(" ")
  874.     end
  875.    
  876.     term.setBackgroundColour(colours.black)
  877.     term.setTextColour(colours.blue)
  878.     term.setCursorPos(2,h)
  879.     term.clearLine()
  880.     term.write("Editor Mode: ")
  881.     term.setTextColour(colours.yellow)
  882.     term.write(levelEditName)
  883.     local msg = "Tool: "..pallette[brushType].n.." "..pallette[brushType].s
  884.     term.setCursorPos(w - #msg - 1, 19)
  885.     term.setTextColour(colours.blue)
  886.     term.write("Tool: ")
  887.     term.setTextColour(colours.yellow)
  888.     term.write(pallette[brushType].n.." ")
  889.     term.setBackgroundColour(pallette[brushType].b)
  890.     term.setTextColour(pallette[brushType].t)
  891.     term.write(pallette[brushType].s)
  892. end
  893.  
  894. local function drawPallette(xpos,ypos)
  895.     local xdim = 7
  896.     local ydim = 5
  897.     local left = xpos
  898.     local top  = ypos
  899.     if xpos + xdim > w then left = left + (w - xpos - xdim) end
  900.     if ypos + ydim > h then top = top + (h - ypos - ydim) end
  901.    
  902.     --There's no easy way to do this... so we draw it manually :(
  903.     for i=0,4 do
  904.         term.setCursorPos(left, top + i)
  905.         term.setBackgroundColour(colours.black)
  906.         term.setTextColour(colours.red)
  907.         if i == 0 or i == 4 then term.write("*-----*")
  908.         else term.write("*     *") end
  909.     end
  910.    
  911.     for i=1,#pallette-1 do
  912.         local ypl = 1
  913.         local xmv = i
  914.         if i > 5 then ypl = 2 xmv = i - 5 end
  915.        
  916.         term.setCursorPos(left + xmv, top+ypl)
  917.         term.setBackgroundColour(pallette[i].b)
  918.         term.setTextColour(pallette[i].t)
  919.         term.write(pallette[i].s)
  920.     end
  921.    
  922.     term.setCursorPos(left + 1, top + 3)
  923.     term.setBackgroundColour(colours.red)
  924.     term.setTextColour(colours.black)
  925.     term.write("ERASE")
  926.    
  927.     local _,button,x,y = os.pullEvent("mouse_click")
  928.    
  929.     if button == 1 then
  930.         if y == top + 1 and x > left and x < left + 6 then
  931.             brushType = x-left
  932.         elseif y == top + 2 and x > left and x < left + 6 then
  933.             brushType = x-left+5
  934.         elseif y == top + 3 and x > left and x < left + 6 then
  935.             brushType = 11
  936.         end
  937.     end
  938.    
  939.     for y = top,top+ydim do
  940.         for x = left,left+xdim do  
  941.             --Not sure why the -2 is necessary
  942.             if map[y+drawOffsetY] then updateMap(x-2,y+drawOffsetY) end
  943.         end
  944.     end
  945.     drawFooter()
  946.     return
  947. end
  948.  
  949. local function saveCurrentMap(path)
  950.     local file = io.open(shell.resolve(".").."/levels/"..path, "w")
  951.     if not file then return false end
  952.    
  953.     drawMap()
  954.     drawFooter()
  955.     local msg = "Saving.."
  956.     term.setCursorPos(w/2-#msg/2, 5)
  957.     term.setTextColour(colours.yellow)
  958.     term.setBackgroundColour(colours.blue)
  959.     term.write(msg)
  960.     term.setCursorPos(w/2-9, 6)
  961.     term.setBackgroundColour(colours.red)
  962.     term.write(string.rep(" ", 18))
  963.     term.setCursorPos(w/2-9,6)
  964.     term.setBackgroundColour(colours.lime)
  965.    
  966.     for y=1,#map do
  967.         local xstr = ""
  968.         for x=1,49 do
  969.             --This again...
  970.                 if map[y][x] == 0 then xstr = xstr..getHexOf(colours.blue)
  971.             elseif map[y][x] == "V" then xstr = xstr..getHexOf(colours.orange)
  972.             elseif map[y][x] == "#" then xstr = xstr..getHexOf(colours.grey)
  973.             elseif map[y][x] == "H" then xstr = xstr..getHexOf(colours.brown)
  974.             elseif map[y][x] == "h" then xstr = xstr..getHexOf(colours.lightGrey)
  975.             elseif map[y][x] == "-" then xstr = xstr..getHexOf(colours.green)
  976.             elseif map[y][x] == "&" then xstr = xstr..getHexOf(colours.red)
  977.             elseif goldMap[y][x] == 1 then xstr = xstr..getHexOf(colours.yellow)
  978.             elseif plX == x and plY == y then xstr = xstr..getHexOf(colours.white)
  979.             elseif exX == x and exY == y then xstr = xstr..getHexOf(colours.lime)
  980.             else xstr = xstr.." "
  981.             end
  982.         end
  983.         file:write(xstr.."\n")
  984.         term.write(" ")
  985.         sleep(0)
  986.     end
  987.     file:close()
  988.     return true
  989. end
  990.  
  991. local function runLevelEditor()
  992.     inLevelEditor = true
  993.     term.setBackgroundColour(colours.black)
  994.     term.clear()
  995.     if not fs.exists(shell.resolve(".").."/levels/"..levelEditName) then
  996.         map = {}
  997.         goldMap = {}
  998.         monks = {}
  999.         for i=1,18 do map[i] = {} goldMap[i] = {} end
  1000.         plX = 2
  1001.         plY = 2
  1002.         plspawnX = plX
  1003.         plspawnY = plY
  1004.         exX = 48
  1005.         exY = 17
  1006.     else
  1007.         loadMap(shell.resolve(".").."/levels/"..levelEditName)
  1008.         for _,monk in pairs(monks) do
  1009.             map[monk.y][monk.x] = "&"
  1010.         end
  1011.         monks = {}
  1012.     end
  1013.    
  1014.     drawMap()
  1015.     drawFooter()
  1016.    
  1017.     while inLevelEditor do
  1018.         local id,button,x,y = os.pullEvent()
  1019.         if id == "mouse_click" or id == "mouse_drag" then
  1020.             if button == 2 then
  1021.                 drawPallette(x,y)
  1022.             elseif x > drawOffsetX and x <= 49 + drawOffsetX and y > drawOffsetY and y <= 18 + drawOffsetY then
  1023.                 if pallette[brushType].v == "player" then
  1024.                     local ox = plX
  1025.                     local oy = plY
  1026.                     if plX == exX and plY == exY then
  1027.                         exX = ox
  1028.                         exY = oy
  1029.                     end
  1030.                     plX = x - drawOffsetX
  1031.                     plY = y - drawOffsetY
  1032.                     map[plY][plX] = nil
  1033.                     goldMap[plY][plX] = nil
  1034.                     updateMap(ox,oy)
  1035.                 elseif pallette[brushType].v == "@" then
  1036.                     local ox = exX
  1037.                     local oy = exY
  1038.                     if plX == exX and plY == exY then
  1039.                         plX = ox
  1040.                         plY = oy
  1041.                     end
  1042.                     exX = x - drawOffsetX
  1043.                     exY = y - drawOffsetY
  1044.                     map[plY][plX] = nil
  1045.                     goldMap[plY][plX] = nil
  1046.                     updateMap(ox,oy)
  1047.                 elseif pallette[brushType].v == "$" then
  1048.                     goldMap[y-drawOffsetY][x-drawOffsetX] = 1
  1049.                     map[y-drawOffsetY][x-drawOffsetX] = nil
  1050.                 elseif pallette[brushType].v == nil then
  1051.                     map[y-drawOffsetY][x-drawOffsetX] = nil
  1052.                     goldMap[y-drawOffsetY][x-drawOffsetX] = nil
  1053.                 else
  1054.                     map[y-drawOffsetY][x-drawOffsetX] = pallette[brushType].v
  1055.                     goldMap[y-drawOffsetY][x-drawOffsetX] = nil
  1056.                     --term.setCursorPos(1,19)
  1057.                     --print("At "..(x-drawOffsetX)..", "..(y-drawOffsetY).." have placed "..pallette[brushType].v)
  1058.                 end
  1059.                 updateMap(x-drawOffsetX, y-drawOffsetY)
  1060.             end
  1061.         elseif id == "mouse_scroll" then
  1062.             brushType = brushType + button
  1063.             if brushType == 0 then brushType = #pallette
  1064.             elseif brushType > #pallette then brushType = 1 end
  1065.             drawFooter()
  1066.         elseif id == "key" and button == keys.enter then
  1067.             menSel = inGameMenu(levelEditOptions)
  1068.             if menSel == "Save" then
  1069.                 saveCurrentMap(levelEditName)
  1070.                 drawMap()
  1071.                 drawFooter()
  1072.             elseif menSel == "Save and Exit" then
  1073.                 saveCurrentMap(levelEditName)
  1074.                 menSel = "none"
  1075.                 inLevelEditor = false
  1076.             elseif menSel == "Discard and Exit" then
  1077.                 menSel = "none"
  1078.                 inLevelEditor = false
  1079.             elseif menSel == "Play Level" then
  1080.                 saveCurrentMap(levelEditName)
  1081.                 inLevelEditor = false
  1082.             end
  1083.         end
  1084.     end
  1085. end
  1086.  
  1087.  
  1088. local function runLevelSelect()
  1089.     if not titleLoaded then
  1090.         loadTitleScreen()
  1091.         monkTimer = os.startTimer(moveIntv * 1.5)
  1092.     else
  1093.         drawMap()
  1094.         drawEndgameMap()
  1095.         term.setCursorPos(1,19)
  1096.         term.setBackgroundColour(colours.blue)
  1097.         term.clearLine()
  1098.     end
  1099.     drawLevelList()
  1100.    
  1101.     menSel = "none"
  1102.     repeat
  1103.         handleEvents()
  1104.        
  1105.         term.setBackgroundColour(colours.black)
  1106.         term.setTextColour(colours.yellow)
  1107.         for i=1,10 do
  1108.             term.setCursorPos(16,3+i)
  1109.             if i == menIndex then
  1110.                 term.write(">")
  1111.             else
  1112.                 term.write(" ")
  1113.             end
  1114.         end
  1115.     until menSel ~= "none"
  1116.     inLevelSelect = false
  1117.     menSel = "New Game"
  1118. end
  1119.  
  1120. local function runTitle()
  1121.     loadTitleScreen()
  1122.     term.setCursorPos(15,3)
  1123.     term.setTextColour(colours.red)
  1124.     term.setBackgroundColour(colours.black)
  1125.     term.write("Gold Runner")
  1126.     term.setCursorPos(16,4)
  1127.     term.write("By Nitrogen Fingers")
  1128.    
  1129.     term.setTextColour(colours.white)
  1130.     for i=1,#titleOptions do
  1131.         term.setCursorPos(19, 5 + (i*2))
  1132.         term.write(titleOptions[i])
  1133.     end
  1134.      
  1135.     term.setCursorPos(16, 7)
  1136.     term.setTextColour(colours.yellow)
  1137.     term.write("->")
  1138.    
  1139.     menSel = "none"
  1140.     monkTimer = os.startTimer(moveIntv * 1.5)
  1141.    
  1142.     repeat
  1143.         handleEvents()
  1144.        
  1145.         term.setBackgroundColour(colours.black)
  1146.         term.setTextColour(colours.yellow)
  1147.         for i=1,#titleOptions do
  1148.             term.setCursorPos(16, 5 + i*2)
  1149.             if menIndex == i then term.write("->")
  1150.             else term.write("  ") end
  1151.         end
  1152.     until menSel ~= "none"
  1153. end
  1154.  
  1155. local function playLevel()
  1156.     loadMap(shell.resolve(".").."/levels/"..levelList[currentLevel])
  1157.     running = true
  1158.     while running do
  1159.         drawMap()
  1160.         drawHUD()
  1161.         os.pullEvent("key")
  1162.         movePlayer(plX,plY,true)
  1163.        
  1164.         monkTimer = os.startTimer(moveIntv * 1.5)
  1165.         moveTimer = os.startTimer(moveIntv)
  1166.         shootTimer = -1
  1167.         spawnTimer = -1
  1168.        
  1169.         started = true
  1170.         while started do
  1171.             handleEvents()
  1172.         end
  1173.        
  1174.         if menSel == "Quit" or menSel == "Back to Title" or menSel == "Edit Level" then
  1175.             running = false
  1176.             return
  1177.         end
  1178.         menSel = "none"
  1179.        
  1180.         if nextLevel then
  1181.             if currentLevel == #levelList then
  1182.                 started = false
  1183.                 running = false
  1184.                 break
  1185.             else
  1186.                 currentLevel = currentLevel + 1
  1187.                 playerLives = playerLives + 1
  1188.                 resetMap()
  1189.                 loadMap(shell.resolve(".").."/levels/"..levelList[currentLevel])
  1190.             end
  1191.             nextLevel = false
  1192.         else
  1193.             playerLives = playerLives-1
  1194.             if playerLives > 0 then resetMap()
  1195.             else
  1196.                 running = false
  1197.             end
  1198.         end
  1199.     end
  1200.    
  1201.     if nextLevel then
  1202.         local msg = "All levels defeated, Gold Runner!"
  1203.         term.setBackgroundColour(colours.black)
  1204.         term.setTextColour(colours.lime)
  1205.         term.setCursorPos(25 - #msg/2, 2)
  1206.         term.write(msg)
  1207.     else
  1208.         local msg = "Game over!"
  1209.         term.setBackgroundColour(colours.black)
  1210.         term.setTextColour(colours.red)
  1211.         term.setCursorPos(25 - #msg/2, 2)
  1212.         term.write(msg)
  1213.     end
  1214.     currentLevel = 1
  1215.     sleep(2)
  1216. end
  1217.  
  1218. term.clear()
  1219. if not fs.exists(shell.resolve(".").."/levels") then
  1220.     error("Level directory not present!")
  1221. end
  1222. levelList = fs.list(shell.resolve(".").."/levels")
  1223. if #levelList == 0 then
  1224.     error("Level directory is empty!")
  1225. end
  1226.  
  1227. runTitle()
  1228. menIndex = 1
  1229.  
  1230. while menSel ~= "Quit" do
  1231.     if menSel == "Select Level" then
  1232.         inLevelSelect = true
  1233.         runLevelSelect()
  1234.     elseif menSel == "New Game" then
  1235.         playerLives = 3
  1236.         playerScore = 0
  1237.         playLevel()
  1238.     elseif menSel == "Create Level" then
  1239.         --This is a bit lazy... well it's all been a bit lazy :P
  1240.         drawMap()
  1241.         term.setCursorPos(1,19)
  1242.         term.setBackgroundColour(colours.blue)
  1243.         term.clearLine()
  1244.        
  1245.         term.setCursorPos(16,10)
  1246.         term.setBackgroundColour(colours.black)
  1247.         term.setTextColour(colours.white)
  1248.         term.write("Enter level name:")
  1249.         term.setTextColour(colours.lime)
  1250.         term.setCursorPos(17,11)
  1251.         term.setCursorBlink(true)
  1252.         local levelName = ""
  1253.        
  1254.         local id,p1
  1255.         repeat
  1256.             id,p1 = os.pullEvent()
  1257.             if id == "key" and p1 == keys.backspace then
  1258.                 levelName = string.sub(levelName, 1, #levelName - 1)
  1259.             elseif id == "timer" and p1 == monkTimer then
  1260.                 updateMonks()
  1261.                 monkTimer = os.startTimer(moveIntv * 2)
  1262.             elseif id == "char" and #levelName < 14 then
  1263.                 levelName = levelName..p1
  1264.             end
  1265.             term.setTextColour(colours.lime)
  1266.             term.setCursorPos(17,11)
  1267.             term.write(levelName..string.rep(" ",14 - #levelName))
  1268.             term.setCursorPos(17 + #levelName ,11)
  1269.         until id == "key" and p1 == keys.enter and #levelName > 0
  1270.        
  1271.         term.setCursorBlink(false)
  1272.         levelEditName = levelName
  1273.         runLevelEditor()
  1274.        
  1275.         if menSel == "Play Level" then
  1276.             currentLevel = nil
  1277.             levelList = fs.list(shell.resolve(".").."/levels")
  1278.             for num,name in pairs(levelList) do
  1279.                 if name == levelName then
  1280.                     currentLevel = num
  1281.                     break
  1282.                 end
  1283.             end
  1284.             menSel = "New Game"
  1285.         else
  1286.             menSel = "none"
  1287.         end
  1288.     elseif menSel == "Edit Level" then
  1289.         levelEditName = levelList[currentLevel]
  1290.         runLevelEditor()
  1291.         term.setBackgroundColour(colours.black)
  1292.         term.clear()
  1293.        
  1294.         if menSel == "Play Level" then
  1295.             menSel = "New Game"
  1296.         else
  1297.             menSel = "none"
  1298.         end
  1299.     elseif menSel == "none" or menSel == "Back to Title" then
  1300.         runTitle()
  1301.     end
  1302.     menIndex = 1
  1303. end
  1304.  
  1305. term.setBackgroundColour(colours.black)
  1306. shell.run("clear")
  1307. term.setTextColour(colours.white)
  1308. print("Thanks for playing Gold Runner!")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement