Guest User

goldrunner

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