Advertisement
Guest User

Gold Runner

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