Advertisement
LDDestroier

TRON (disknet)

May 1st, 2019
348
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 59.60 KB | None | 0 0
  1. --[[
  2.     TRON Light Cycle Game
  3.     programmed by LDDestroier
  4.      Get with:
  5.     wget https://raw.githubusercontent.com/LDDestroier/CC/master/tron.lua
  6. --]]
  7.  
  8. local port = 701
  9. local kioskMode = false         -- disables options menu
  10. local useLegacyMouseControl = false -- if true, click move regions will be divided into diagonal quadrants
  11.  
  12. local scr_x, scr_y = term.getSize()
  13. local scr_mx, scr_my = scr_x / 2, scr_y / 2
  14. local isColor = term.isColor()
  15. local doShowByImage = true  -- show "By LDDestroier" in title
  16.  
  17. local gameDelayInit = 0.1   -- lower value = faster game. I recommend 0.1 for SMP play.
  18. local doDrawPlayerNames = true  -- draws the names of players onscreen
  19. local doRenderOwnName = false   -- if doDrawPlayerNames, also draws your own name
  20. local useSetVisible = false -- use term.current().setVisible, which speeds things up at the cost of multishell
  21. local gridID = 1        -- determines which grid is used
  22. local mode = "menu"
  23.  
  24. local disknet = dofile("disknet.lua")
  25.  
  26. -- initial grid information, (hopefully) transferred to non-host players
  27. local initGrid = {
  28.     x1 = -100,
  29.     y1 = -100,
  30.     x2 = 100,
  31.     y2 = 100,
  32.     border = "#",
  33.     voidcol = "f",
  34.     forecol = "8",
  35.     backcol = "7",
  36.     edgecol = "0"
  37. }
  38. local resetPlayers = function()
  39.     return {
  40.         [1] = {
  41.             num = 1,
  42.             x = -3,
  43.             y = -5,
  44.             direction = -1,
  45.             char = "@",
  46.             color = {
  47.                 colors.blue,
  48.                 colors.blue,
  49.                 colors.blue,
  50.                 colors.cyan,
  51.                 colors.cyan,
  52.                 colors.lightBlue,
  53.                 colors.lightBlue,
  54.                 colors.cyan,
  55.                 colors.cyan
  56.             },
  57.             dead = false,
  58.             trailLevel = 10,
  59.             trailMax = 10,
  60.             trailRegen = 0.1,
  61.             putTrail = true,
  62.             name = "BLU",
  63.             initName = "BLU"
  64.         },
  65.         [2] = {
  66.             num = 2,
  67.             x = 3,
  68.             y = -5,
  69.             direction = -1,
  70.             char = "@",
  71.             color = {
  72.                 colors.red,
  73.                 colors.red,
  74.                 colors.red,
  75.                 colors.orange,
  76.                 colors.orange,
  77.                 colors.yellow,
  78.                 colors.yellow,
  79.                 colors.orange,
  80.                 colors.orange
  81.             },
  82.             dead = false,
  83.             trailLevel = 10,
  84.             trailMax = 10,
  85.             trailRegen = 0.1,
  86.             putTrail = true,
  87.             name = "RED",
  88.             initName = "RED"
  89.         }
  90.     }
  91. end
  92.  
  93. local function interpretArgs(tInput, tArgs)
  94.     local output = {}
  95.     local errors = {}
  96.     local usedEntries = {}
  97.     for aName, aType in pairs(tArgs) do
  98.         output[aName] = false
  99.         for i = 1, #tInput do
  100.             if not usedEntries[i] then
  101.                 if tInput[i] == aName and not output[aName] then
  102.                     if aType then
  103.                         usedEntries[i] = true
  104.                         if type(tInput[i+1]) == aType or type(tonumber(tInput[i+1])) == aType then
  105.                             usedEntries[i+1] = true
  106.                             if aType == "number" then
  107.                                 output[aName] = tonumber(tInput[i+1])
  108.                             else
  109.                                 output[aName] = tInput[i+1]
  110.                             end
  111.                         else
  112.                             output[aName] = nil
  113.                             errors[1] = errors[1] and (errors[1] + 1) or 1
  114.                             errors[aName] = "expected " .. aType .. ", got " .. type(tInput[i+1])
  115.                         end
  116.                     else
  117.                         usedEntries[i] = true
  118.                         output[aName] = true
  119.                     end
  120.                 end
  121.             end
  122.         end
  123.     end
  124.     for i = 1, #tInput do
  125.         if not usedEntries[i] then
  126.             output[#output+1] = tInput[i]
  127.         end
  128.     end
  129.     return output, errors
  130. end
  131.  
  132. local argData = {
  133.     ["skynet"] = false, -- use Skynet HTTP multiplayer
  134.     ["quick"] = false,  -- start one game immediately
  135.     ["griddemo"] = false,   -- only move the grid
  136.     ["--update"] = false,   -- updates TRON to the latest version
  137.     ["--gridID"] = "number" -- grid ID to use
  138. }
  139.  
  140. local gridFore, gridBack
  141. local gridList = {
  142.     [1] = {     -- broken up and cool looking
  143.         {
  144.             "+-    -+------",
  145.             "|      |      ",
  146.             "       |      ",
  147.             ".      |      ",
  148.             "+------+-   --",
  149.             "|      |      ",
  150.             "|             ",
  151.             "|      .      ",
  152.         },
  153.         {
  154.             "+-      -+--------",
  155.             "|        |        ",
  156.             "         |        ",
  157.             "         |        ",
  158.             "         |        ",
  159.             "|        |        ",
  160.             "+--------+-      -",
  161.             "|        |        ",
  162.             "|                 ",
  163.             "|                 ",
  164.             "|                 ",
  165.             "|        |        ",
  166.         }
  167.     },
  168.     [2] = {     -- flat diagonal sorta
  169.         {
  170.             "    /      ",
  171.             "   /       ",
  172.             "  /        ",
  173.             " /         ",
  174.             "/__________"
  175.         },
  176.         {
  177.             "       /        ",
  178.             "      /         ",
  179.             "     /          ",
  180.             "    /           ",
  181.             "   /            ",
  182.             "  /             ",
  183.             " /              ",
  184.             "/_______________"
  185.         }
  186.     },
  187.     [3] = {     -- basic simple grid
  188.         {
  189.             "+-------",
  190.             "|       ",
  191.             "|       ",
  192.             "|       ",
  193.             "|       "
  194.         },
  195.         {
  196.             "+------------",
  197.             "|            ",
  198.             "|            ",
  199.             "|            ",
  200.             "|            ",
  201.             "|            ",
  202.             "|            ",
  203.             "|            "
  204.         }
  205.     },
  206.     [4] = {     -- diamond grid
  207.         {
  208.             "   /\\   ",
  209.             "  /  \\  ",
  210.             " /    \\ ",
  211.             "/      \\",
  212.             "\\      /",
  213.             " \\    / ",
  214.             "  \\  /  ",
  215.             "   \\/   ",
  216.         },
  217.         {
  218.             "     /\\     ",
  219.             "    /  \\    ",
  220.             "   /    \\   ",
  221.             "  /      \\  ",
  222.             " /        \\ ",
  223.             "/          \\",
  224.             "\\          /",
  225.             " \\        / ",
  226.             "  \\      /  ",
  227.             "   \\    /   ",
  228.             "    \\  /    ",
  229.             "     \\/     ",
  230.         }
  231.     },
  232.     [5] = {     -- brick and mortar
  233.         {
  234.             "|          ",
  235.             "|          ",
  236.             "|          ",
  237.             "|          ",
  238.             "===========",
  239.             "     |     ",
  240.             "     |     ",
  241.             "     |     ",
  242.             "     |     ",
  243.             "===========",
  244.         },
  245.         {
  246.             "|      ",
  247.             "|      ",
  248.             "=======",
  249.             "   |   ",
  250.             "   |   ",
  251.             "=======",
  252.         },
  253.     },
  254.     [6] = {     -- pain background
  255.         {
  256.             "@                                                   ",
  257.             "@                                                   ",
  258.             "@                                                   ",
  259.             "@                                                   ",
  260.             "@                                                   ",
  261.             "@                                                   ",
  262.             "@                                                   ",
  263.             "@                                                   ",
  264.             "@                                                   ",
  265.             "@                                                   ",
  266.             "@                                                   ",
  267.             "@                                                   ",
  268.             "@                                                   ",
  269.             "@                                                   ",
  270.             "@                                                   ",
  271.             "@                                                   ",
  272.             "@                                                   ",
  273.             "@                                                   ",
  274.             "@                                                   ",
  275.             "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@SCREEN@MAX@",
  276.         },
  277.         {
  278.             "%%..",
  279.             "%%..",
  280.             "%%..",
  281.             "..%%",
  282.             "..%%",
  283.             "..%%"
  284.         },
  285.     },
  286.     [7] = {     -- some
  287.         {
  288.             " "
  289.         },
  290.         {
  291.             "+-----------------------------------------------------",
  292.             "|   Somebody once told me the world is gonna roll me  ",
  293.             "|   I ain't the sharpest tool in the shed / She was   ",
  294.             "| looking kind of dumb with her finger and her thumb  ",
  295.             "|  In the shape of an \"L\" on her forehead / Well the  ",
  296.             "|    years start coming and they don't stop coming    ",
  297.             "|    Fed to the rules and I hit the ground running    ",
  298.             "| Didn't make sense not to live for fun / Your brain  ",
  299.             "|   gets smart but your head gets dumb / So much to   ",
  300.             "|  do, so much to see / So what's wrong with taking   ",
  301.             "| the back streets? / You'll never know if you don't  ",
  302.             "|   go / You'll never shine if you don't glow / Hey   ",
  303.             "| now, you're an all-star, get your game on, go play  ",
  304.             "|  Hey now, you're a rock star, get the show on, get  ",
  305.             "|     paid / And all that glitters is gold / Only     ",
  306.             "|  shooting stars break the mold / It's a cool place  ",
  307.             "|   and they say it gets colder / You're bundled up   ",
  308.             "|  now, wait till you get older / But the meteor men  ",
  309.             "|      beg to differ / Judging by the hole in the     ",
  310.             "|   satellite picture / The ice we skate is getting   ",
  311.             "| pretty thin / The water's getting warm so you might ",
  312.             "| as well swim / My world's on fire, how about yours? ",
  313.             "|    That's the way I like it and I never get bored   ",
  314.             "|  Hey now, you're an all-star, get your game on, go  ",
  315.             "|  play / Hey now, you're a rock star, get the show   ",
  316.             "|   on, get paid / All that glitters is gold / Only   ",
  317.             "|   shooting stars break the mold / Hey now, you're   ",
  318.             "|  an all-star, get your game on, go play / Hey now,  ",
  319.             "|    you're a rock star, get the show, on get paid    ",
  320.             "|    And all that glitters is gold / Only shooting    ",
  321.             "|  stars... / Somebody once asked could I spare some  ",
  322.             "|  change for gas? / I need to get myself away from   ",
  323.             "|  this place / I said yep, what a concept / I could  ",
  324.             "|  use a little fuel myself / And we could all use a  ",
  325.             "|   little change / Well, the years start coming and  ",
  326.             "|   they don't stop coming / Fed to the rules and I   ",
  327.             "|  hit the ground running / Didn't make sense not to  ",
  328.             "| live for fun / Your brain gets smart but your head  ",
  329.             "|   gets dumb / So much to do, so much to see / So    ",
  330.             "|     what's wrong with taking the back streets?      ",
  331.             "|   You'll never know if you don't go (go!) / You'll  ",
  332.             "|   never shine if you don't glow / Hey now, you're   ",
  333.             "|  an all-star, get your game on, go play / Hey now,  ",
  334.             "|    you're a rock star, get the show on, get paid    ",
  335.             "|    And all that glitters is gold / Only shooting    ",
  336.             "|   stars break the mold / And all that glitters is   ",
  337.             "|      gold / Only shooting stars break the mold      ",
  338.         }
  339.     }
  340. }
  341.  
  342. local argList = interpretArgs({...}, argData)
  343.  
  344. local useSkynet = argList["skynet"]
  345. local useOnce = argList["quick"]
  346. local doGridDemo = argList["griddemo"]
  347. local doUpdateGame = argList["--update"]
  348. if gridList[argList["--gridID"]] then
  349.     gridID = argList["--gridID"]
  350. end
  351. local argumentName = argList[1]
  352. local argumentPassword = argList[2] or ""
  353.  
  354. if useSkynet and (not http.websocket) then
  355.     error("Skynet is not supported on this version of ComputerCraft.")
  356. end
  357.  
  358. local skynetPath = fs.combine(fs.getDir(shell.getRunningProgram()), "skynet.lua")
  359. local skynetURL = "https://raw.githubusercontent.com/osmarks/skynet/master/client.lua"
  360.  
  361. if argumentName then
  362.     argumentName = argumentName:sub(1, 15) -- gotta enforce that limit
  363. end
  364.  
  365. local toblit = {
  366.     [0] = " ",
  367.     [colors.white] = "0",
  368.     [colors.orange] = "1",
  369.     [colors.magenta] = "2",
  370.     [colors.lightBlue] = "3",
  371.     [colors.yellow] = "4",
  372.     [colors.lime] = "5",
  373.     [colors.pink] = "6",
  374.     [colors.gray] = "7",
  375.     [colors.lightGray] = "8",
  376.     [colors.cyan] = "9",
  377.     [colors.purple] = "a",
  378.     [colors.blue] = "b",
  379.     [colors.brown] = "c",
  380.     [colors.green] = "d",
  381.     [colors.red] = "e",
  382.     [colors.black] = "f"
  383. }
  384. local tograyCol, tograyBlit = {
  385.     [0] = 0,
  386.     [colors.white] = colors.white,
  387.     [colors.orange] = colors.lightGray,
  388.     [colors.magenta] = colors.lightGray,
  389.     [colors.lightBlue] = colors.white,
  390.     [colors.yellow] = colors.white,
  391.     [colors.lime] = colors.lightGray,
  392.     [colors.pink] = colors.lightGray,
  393.     [colors.gray] = colors.gray,
  394.     [colors.lightGray] = colors.lightGray,
  395.     [colors.cyan] = colors.lightGray,
  396.     [colors.purple] = colors.gray,
  397.     [colors.blue] = colors.gray,
  398.     [colors.brown] = colors.gray,
  399.     [colors.green] = colors.gray,
  400.     [colors.red] = colors.white,
  401.     [colors.black] = colors.black
  402. }, {}
  403.  
  404. local tocolors = {}
  405. for k,v in pairs(toblit) do
  406.     tocolors[v] = k
  407. end
  408. for k,v in pairs(tograyCol) do
  409.     tograyBlit[toblit[k]] = toblit[v]
  410. end
  411.  
  412. local termwrite, termclear = term.write, term.clear
  413. local termsetCursorPos, termgetCursorPos = term.setCursorPos, term.getCursorPos
  414. local tableunpack, tableremove = unpack, table.remove
  415. local mathfloor, mathceil, mathcos, mathsin, mathrandom, mathrad = math.floor, math.ceil, math.cos, math.sin, math.random, math.rad
  416.  
  417. local termsetTextColor = function(col)
  418.     return term.setTextColor(isColor and col or tograyCol[col])
  419. end
  420.  
  421. local termsetBackgroundColor = function(col)
  422.     return term.setBackgroundColor(isColor and col or tograyCol[col])
  423. end
  424.  
  425. local termblit = function(char, text, back)
  426.     if isColor then
  427.         return term.blit(char, text, back)
  428.     else
  429.         return term.blit(
  430.             char,
  431.             text:gsub(".", tograyBlit),
  432.             back:gsub(".", tograyBlit)
  433.         )
  434.     end
  435. end
  436.  
  437. local tsv = function(visible)
  438.     if term.current().setVisible and useSetVisible then
  439.         term.current().setVisible(visible)
  440.     end
  441. end
  442.  
  443. local round = function(num, places)
  444.     return math.floor(num * 10^places + 0.5) / 10^places
  445. end
  446.  
  447. if doUpdateGame then
  448.     print("Downloading...")
  449.     local net = http.get("https://github.com/LDDestroier/CC/raw/master/tron.lua")
  450.     if net then
  451.         local file = fs.open(shell.getRunningProgram(), "w")
  452.         file.write(net.readAll())
  453.         file.close()
  454.         print("Updated!")
  455.     else
  456.         printError("Couldn't update!")
  457.     end
  458.     if useOnce then
  459.         return
  460.     else
  461.         sleep(0.2)
  462.         shell.run( shell.getRunningProgram(), table.concat({...}, " "):gsub("--update", "") )
  463.         return
  464.     end
  465. end
  466.  
  467. local cwrite = function(text, y, xdiff, wordPosCheck)
  468.     wordPosCheck = wordPosCheck or #text
  469.     termsetCursorPos(mathfloor(scr_x / 2 - math.floor(0.5 + #text + (xdiff or 0)) / 2), y or (scr_y - 2))
  470.     term.write(text)
  471.     return (scr_x / 2) - (#text / 2) + wordPosCheck
  472. end
  473.  
  474. local modem, skynet
  475. local setUpModem = function()
  476.     if not doGridDemo then
  477.         --[[
  478.         if useSkynet then
  479.             if fs.exists(skynetPath) then
  480.                 skynet = dofile(skynetPath)
  481.                 term.clear()
  482.                 cwrite("Connecting to Skynet...", scr_y / 2)
  483.                 skynet.open(port)
  484.             else
  485.                 term.clear()
  486.                 cwrite("Downloading Skynet...", scr_y / 2)
  487.                 local prog = http.get(skynetURL)
  488.                 if prog then
  489.                     local file = fs.open(skynetPath, "w")
  490.                     file.write(prog.readAll())
  491.                     file.close()
  492.                     skynet = dofile(skynetPath)
  493.                     cwrite("Connecting to Skynet...", 1 + scr_y / 2)
  494.                     skynet.open(port)
  495.                 else
  496.                     error("Could not download Skynet.")
  497.                 end
  498.             end
  499.         else
  500.             modem = peripheral.find("modem")
  501.             if (not modem) and ccemux then
  502.                 ccemux.attach("top", "wireless_modem")
  503.                 modem = peripheral.find("modem")
  504.             end
  505.             if modem then
  506.                 modem.open(port)
  507.             else
  508.                 error("You should attach a modem.")
  509.             end
  510.         end
  511.         --]]
  512.         disknet.open(port)
  513.     end
  514. end
  515. setUpModem()
  516.  
  517. local transmit = function(port, message)
  518.     disknet.send(port, message)
  519.     --[[
  520.     if useSkynet then
  521.         skynet.send(port, message)
  522.     else
  523.         modem.transmit(port, port, message)
  524.     end
  525.     --]]
  526. end
  527.  
  528. local gamename = ""
  529. local isHost
  530.  
  531. local waitingForGame = true
  532.  
  533. -- used in skynet matches if you are player 2
  534. local ping = 0
  535.  
  536. local copyTable
  537. copyTable = function(tbl, ...)
  538.     local output = {}
  539.     for k,v in pairs(tbl) do
  540.         if type(v) == "table" then
  541.             output[k] = copyTable(v)
  542.         else
  543.             output[k] = v
  544.         end
  545.     end
  546.     for i = 1, #arg do
  547.         output[#output+1] = arg[i]
  548.     end
  549.     return output
  550. end
  551.  
  552. grid = copyTable(initGrid)
  553.  
  554. local you, nou = 1, 2
  555.  
  556. local keysDown, netKeysDown = {}, {}
  557. local miceDown = {}
  558.  
  559. local lastDirectionPressed, netLastDirectionPressed
  560.  
  561. -- the scrolling of the screen
  562. local scrollX = 0
  563. local scrollY = 0
  564.  
  565. -- used when panning with WASD
  566. local scrollAdjX = 0
  567. local scrollAdjY = 0
  568.  
  569. local lockInput = false
  570. local player
  571.  
  572. player = resetPlayers()
  573.  
  574. local images
  575. if _HOST then -- need to add some NFP image replacements for older versions of CC
  576.     images = {
  577.         logo = {
  578.             {
  579.                 " •ƒƒƒƒƒƒƒƒƒ•—ƒƒƒƒƒƒƒ‹‹   ‡‡ƒƒƒ‹‹  Ÿ‹    •ƒƒ•",
  580.                 " •ƒƒƒ”€—ƒƒƒ•‚ƒƒƒƒƒ‹€€€Š —€Ÿƒƒƒ€” •‚‚  •€€•",
  581.                 "     •€•          ‚‚ƒƒ•€€—€€€”€€••€€‹‹ •€€•",
  582.                 "     •€•    —ƒ”‹“ƒƒ‹€€€•€€•€€€•€€••€•ˆƒ€€•",
  583.                 "     •€•    •€• ‚‹€€‹€Š€‹‡€Ÿ…•€•  ‚‚€•",
  584.                 "     •€•    •€•   ‹€‚‹ ‹‹€€€Ÿ‡‡ •€•    ‹‹•",
  585.                 "             Š  ‚‹‡       ‚…",
  586.             },
  587.             {
  588.                 " f7777777777777777777f   f77777f  7f    f777",
  589.                 " f99979999979999999999f 799999799 77f7  f997",
  590.                 "     799          79999f997    9977997f f997",
  591.                 "     799    7797777fffff997    9977997797997",
  592.                 "     799    799 799977f7797fff7997799  79797",
  593.                 "     799    799   7797f 797999997 799    797",
  594.                 "     777    777    7777  7777777  777     77",
  595.             },
  596.             {
  597.                 " 7999999999f9999999997   7999997  97    799f",
  598.                 " 7777997777f77777779997 997777997 997f  799f",
  599.                 "     997          f7777799    799f99997 799f",
  600.                 "     997    997f9997fff799    799f997ff7999f",
  601.                 "     997    997 f7999fff999777997f997  f799f",
  602.                 "     997    997   f9997 f7999977f 997    f7f",
  603.                 "     fff    fff    ffff  fffffff  fff     ff",
  604.             }
  605.         },
  606.         win = {
  607.             {
  608.                 "€•€€€€€€€••€€€€€€€€Š€€€€•€€€•",
  609.                 "€•€€€€€€€•‚€€•€ƒ€€€‚€€•€€€•",
  610.                 "€•€€‡€€€•€€€€•€€€€•‹€‹€•€€€•",
  611.                 "€•ŸŸ€‹€€•€€€€•€€€€•€‚‚…€€€•",
  612.                 "€‚€‡€‚‚€•Ÿ€€•€€€•€€€‹€€€",
  613.                 "€Ÿ€€€€‹€••€€€€€€€€•€€€€•€€€•",
  614.             },
  615.             {
  616.                 "55      55 555555 5      5 55",
  617.                 "55      5555 55 5 55 5   5 55",
  618.                 "55   5  55   55   5555   5 55",
  619.                 "55  55  55   55   55 5   5 55",
  620.                 "5 55 5  55 5 55   55   555  5",
  621.                 "555    555 555555 55     5 55",
  622.             },
  623.             {
  624.                 "5       5 5555555 55    55 5 ",
  625.                 "5       5    5    555   55 5 ",
  626.                 "5   5   5    5    5  55 55 5 ",
  627.                 "5 55 55 5    5    5   5555 5 ",
  628.                 "555   555 5  5  5 5     55 5 ",
  629.                 "5       5 5555555 5     55 5 ",
  630.             }
  631.         },
  632.         lose = {
  633.             {
  634.                 "€•€€€€€€Ÿ€€€‚€€€€€€‚€€€€€€€€",
  635.                 "€•€€€€€€€Ÿ€‚€€€—€€€‚ƒ€€•€€€‚ƒ",
  636.                 "€•€€€€€€€•€€€•€€€€ƒƒƒƒ‹€€‚ƒƒƒ”€",
  637.                 "€•€€€€€€€•€€€•€€‚ƒƒƒƒ€€€—ƒƒƒ€",
  638.                 "€•€€€€€€€‚€Ÿ€€€€€…€€€•€€€Ÿ",
  639.                 "€€€€€€€€‚€€€Ÿ€€€€€€Ÿ€€€€€€€€",
  640.             },
  641.             {
  642.                 "ee        eee e  eeeee  eeeeeee",
  643.                 "ee      eee e e ee   ee ee   ee",
  644.                 "ee      ee    e ee      e    e ",
  645.                 "ee      ee    e eeeee e eeeeee ",
  646.                 "ee      e e   e  e    e ee     ",
  647.                 "eeeeeee e eeeee  eeeeee eeeeeee",
  648.             },
  649.             {
  650.                 "e       eeeeee  eeeeeee eeeeeee",
  651.                 "e       e    ee e       e      ",
  652.                 "e       e    ee eeeeeee eeeee  ",
  653.                 "e       e    ee      ee e      ",
  654.                 "e       ee  eee e    ee e    ee",
  655.                 "eeeeeee  eeee   eeeeee  eeeeeee",
  656.             }
  657.         },
  658.         tie = {
  659.             {
  660.                 "€€€€€€€••€€€€€€€€€€€€€€€",
  661.                 "€€€€•€€€‚€•€€€ƒ€€•€€€€ƒ",
  662.                 "€€€€•€€€€€€•€€€€€€‚ƒƒƒ”€",
  663.                 "€€€€•€€€€€€•€€€€€€—ƒƒƒ€",
  664.                 "€€€€•€€€Ÿ€•€€€€€•€€€€",
  665.                 "€€€€•€€€•€€€€€€€€€€€€€€€",
  666.             },
  667.             {
  668.                 "77888800 0000000 0888877",
  669.                 "   88   00  0  0 08    7",
  670.                 "   88       0    0    7 ",
  671.                 "   88       0    088887 ",
  672.                 "   88    0  0    08     ",
  673.                 "   88    0000000 0888877",
  674.             },
  675.             {
  676.                 "7788880 00000000 0888877",
  677.                 "   8       00    0      ",
  678.                 "   8       00    08888  ",
  679.                 "   8       00    0      ",
  680.                 "   8    0  00  0 0     7",
  681.                 "   8    00000000 0888877",
  682.             },
  683.         },
  684.         timeout = {
  685.             {
  686.                 "—ƒƒƒƒ•—ƒƒƒƒ•—ƒ›Ÿ†ƒ•—ƒƒƒ”",
  687.                 "“€—Œ…“€—Œ…•€€€€••€ŒŒž",
  688.                 " •€•€€…€••€˜•€••€ˆŒŽ",
  689.                 " •€•€€•€€€€••€•€•€••€€€•",
  690.                 " ‚ƒƒ€€ƒƒƒƒƒƒƒ€ƒƒƒƒƒƒƒ",
  691.                 "   —ƒƒƒƒ••ƒ”•ƒ”•ƒƒƒƒ”",
  692.                 "   •€œ”€••€••€•ŠŒ”€œŽ",
  693.                 "   •€Š•€••€•…€• €•€•",
  694.                 "   •€€€€••€€€€• €•€•",
  695.                 "   ƒƒƒƒƒ‚ƒƒƒƒƒ€€ƒƒ",
  696.             },
  697.             {
  698.                 "00000000000000ff0000000f",
  699.                 "0fff000fff000ff0ff00f000",
  700.                 "0ffffffffff00f000f00ffff",
  701.                 " fffff0ffff00f0f0f00ffff",
  702.                 " 000ff000000000f00000000",
  703.                 "   000000f0ff0ff0000f",
  704.                 "   0f00f0ffffff000f00",
  705.                 "   0ff0f0ffffff7f0f0",
  706.                 "   0ffff0ffffff7f0f0",
  707.                 "   000000000000ff000",
  708.             },
  709.             {
  710.                 "ffffffffffffff00fffffff0",
  711.                 " 0f0fff0f0ffffffffffffff",
  712.                 " 0f0ff00f00ffffffffff000",
  713.                 " 0f0fffffffffffffffffff0",
  714.                 " fffffffffffffffffffffff",
  715.                 "   ffffff0f00f00ffff0",
  716.                 "   ffffff0f00f0ffffff",
  717.                 "   ff0fff0f00f0fffff",
  718.                 "   ffffff0ffff0fffff",
  719.                 "   fffffffffffffffff",
  720.             },
  721.         },
  722.         ldd = {
  723.             {
  724.                 "                                               ",
  725.                 " ƒŒ‹—”—”   —œ“€ƒ‚•ˆŒ‡ŒŒŸŸœ“ƒ€ƒ•ˆŒƒŒ‹",
  726.                 " €ƒ‚ ”—  €  ••••€Ÿ•Šƒ‚ •• €Œˆ••••€•Š€ƒ‚",
  727.                 " ƒƒ ‚  ŒŒ‚ƒƒ        ‚ƒ Š…   ƒƒ        ƒ ƒ",
  728.             },
  729.             {
  730.                 "                                               ",
  731.                 " f7ff7f7 f  fbfbbbffff9f99fff9ff9f9f9999fff9f9f",
  732.                 " 77f f7  b  fbfbbfbfff9f9f f9 99ff9f9f9ffff999f",
  733.                 " 777 77  bbbbbb        999 99 9 9 99        9 9",
  734.             },
  735.             {
  736.                 "                                               ",
  737.                 " 7f77f7f b  bfbfbfb999f9ff999f99f9f9ff9f999f9f9",
  738.                 " 7f7 7f  b  bfbfbbf999f9f9 9f 9f99f9f999999f9f9",
  739.                 " fff ff  ffffff        fff ff f f ff        f f",
  740.             },
  741.         }
  742.     }
  743. else
  744.     images = {
  745.         logo = {
  746.             {
  747.                 "                                          ",
  748.                 "                                          ",
  749.                 "                                          ",
  750.                 "                                          ",
  751.                 "                                          ",
  752.                 "                                          ",
  753.                 "                                          ",
  754.             },
  755.             {
  756.                 "7777777777 77777777    77777777  77     77",
  757.                 "    77           777  777    777 777    77",
  758.                 "    77            777 77      77 7777   77",
  759.                 "    77     7777777    77      77 77777  77",
  760.                 "    77     77  7777   77      77 77   7777",
  761.                 "    77     77   7777  777    777 77    777",
  762.                 "    77     77    7777  77777777  77     77",
  763.             },
  764.             {
  765.                 "9999999999 99999999    99999999  99     99",
  766.                 "    99           999  999    999 999    99",
  767.                 "    99            999 99      99 9999   99",
  768.                 "    99     9999999    99      99 99999  99",
  769.                 "    99     99  9999   99      99 99   9999",
  770.                 "    99     99   9999  999    999 99    999",
  771.                 "    99     99    9999  99999999  99     99",
  772.             },
  773.         },
  774.         win = {
  775.             {
  776.                 "                            ",
  777.                 "                            ",
  778.                 "                            ",
  779.                 "                            ",
  780.                 "                            ",
  781.                 "                            ",
  782.                 "                            ",
  783.             },
  784.             {
  785.                 "77     77 777777 77    77 77",
  786.                 "77     77 777777 777   77 77",
  787.                 "77  7  77   77   7777  77 77",
  788.                 "77 777 77   77   77 77 77 77",
  789.                 "7777 7777   77   77  7777   ",
  790.                 "777   777 777777 77   777 77",
  791.                 "77     77 777777 77    77 77",
  792.             },
  793.             {
  794.                 "55     55 555555 55    55 55",
  795.                 "55     55 555555 555   55 55",
  796.                 "55  5  55   55   5555  55 55",
  797.                 "55 555 55   55   55 55 55 55",
  798.                 "5555 5555   55   55  5555   ",
  799.                 "555   555 555555 55   555 55",
  800.                 "55     55 555555 55    55 55",
  801.             },
  802.         },
  803.         lose = {
  804.             {
  805.                 "                           ",
  806.                 "                           ",
  807.                 "                           ",
  808.                 "                           ",
  809.                 "                           ",
  810.                 "                           ",
  811.                 "                           ",
  812.                 "                           ",
  813.             },
  814.             {
  815.                 "77     777777   77777 77777",
  816.                 "77    77777777 777777 77777",
  817.                 "77    777  777 77     77   ",
  818.                 "77    77    77 77777  7777 ",
  819.                 "77    77    77  77777 77   ",
  820.                 "77    777  777     77 77   ",
  821.                 "77777 77777777 777777 77777",
  822.                 "77777  777777  77777  77777",
  823.             },
  824.             {
  825.                 "ee     eeeeee   eeeee eeeee",
  826.                 "ee    eeeeeeee eeeeee eeeee",
  827.                 "ee    eee  eee ee     ee   ",
  828.                 "ee    ee    ee eeeee  eeee ",
  829.                 "ee    ee    ee  eeeee ee   ",
  830.                 "ee    eee  eee     ee ee   ",
  831.                 "eeeee eeeeeeee eeeeee eeeee",
  832.                 "eeeee  eeeeee  eeeee  eeeee",
  833.             },
  834.         },
  835.         tie = {
  836.             {
  837.                 "                         ",
  838.                 "                         ",
  839.                 "                         ",
  840.                 "                         ",
  841.                 "                         ",
  842.                 "                         ",
  843.                 "                         ",
  844.             },
  845.             {
  846.                 "77777777 77777777 7777777",
  847.                 "   77       77    77     ",
  848.                 "   77       77    77     ",
  849.                 "   77       77    777777 ",
  850.                 "   77       77    77     ",
  851.                 "   77       77    77     ",
  852.                 "   77    77777777 7777777",
  853.             },
  854.             {
  855.                 "77888800 00000000 0888877",
  856.                 "   88       00    08     ",
  857.                 "   88       00    08     ",
  858.                 "   88       00    088887 ",
  859.                 "   88       00    08     ",
  860.                 "   88       00    08     ",
  861.                 "   88    00000000 0888877",
  862.             },
  863.         },
  864.         timeout = {
  865.             {
  866.                 "                            ",
  867.                 "                            ",
  868.                 "                            ",
  869.                 "                            ",
  870.                 "                            ",
  871.                 "                            ",
  872.                 "                            ",
  873.                 "                            ",
  874.                 "                            ",
  875.                 "                            ",
  876.                 "                            ",
  877.                 "                            ",
  878.                 "                            ",
  879.                 "                            ",
  880.                 "                            ",
  881.                 "                            ",
  882.             },
  883.             {
  884.                 "7777777 777 777   777 777777",
  885.                 "7777777 777 7777 7777 777777",
  886.                 "7777777 777 777777777 777777",
  887.                 "  777   777 777777777 77777 ",
  888.                 "  777   777 777777777 777777",
  889.                 "  777   777 777777777 777777",
  890.                 "  777   777 777   777 777777",
  891.                 "                            ",
  892.                 "   7777777 777 777 7777777  ",
  893.                 "   7777777 777 777 7777777  ",
  894.                 "   7777777 777 777 7777777  ",
  895.                 "   777 777 777 777   777    ",
  896.                 "   777 777 777 777   777    ",
  897.                 "   7777777 7777777   777    ",
  898.                 "   7777777 7777777   777    ",
  899.                 "   7777777 7777777   777    ",
  900.             },
  901.             {
  902.                 "0000000 000 000   000 000000",
  903.                 "0fffff0 0f0 0ff0 0ff0 0ffff0",
  904.                 "000f000 0f0 0fff0fff0 0f0000",
  905.                 "  0f0   0f0 0f0fff0f0 0fff0 ",
  906.                 "  0f0   0f0 0f00f00f0 0f0000",
  907.                 "  0f0   0f0 0f00000f0 0ffff0",
  908.                 "  000   000 000   000 000000",
  909.                 "                            ",
  910.                 "   0000000 000 000 0000000  ",
  911.                 "   0fffff0 0f0 0f0 0fffff0  ",
  912.                 "   0f000f0 0f0 0f0 000f000  ",
  913.                 "   0f0 0f0 0f0 0f0   0f0    ",
  914.                 "   0f0 0f0 0f0 0f0   0f0    ",
  915.                 "   0f000f0 0f000f0   0f0    ",
  916.                 "   0fffff0 0fffff0   0f0    ",
  917.                 "   0000000 0000000   000    ",
  918.             },
  919.         },
  920.         ldd = {
  921.             {
  922.                 "                                          ",
  923.                 "                                          ",
  924.                 "                                          ",
  925.                 "                                          ",
  926.                 "                                          ",
  927.                 "                                          ",
  928.                 "                                          ",
  929.                 "                                          ",
  930.                 "                                          ",
  931.                 "                                          ",
  932.                 "                                          ",
  933.             },
  934.             {
  935.                 "               777 7 7                    ",
  936.                 "               7 7 7 7                    ",
  937.                 "               77   7                     ",
  938.                 "               7 7  7                     ",
  939.                 "    77  77     777  7      777 777        ",
  940.                 "7   7 7 7 7 77         777 7 7  7  777    ",
  941.                 "7   7 7 7 7 7  777 777 7 7 7 7  7  7   777",
  942.                 "7   7 7 7 7 77 7    7  77  7 7  7  77  7 7",
  943.                 "7   77  77  7  777  7  7 7 777 777 7   77 ",
  944.                 "777         77   7  7  7 7         777 7 7",
  945.                 "               777  7                  7 7",
  946.             },
  947.             {
  948.                 "               777 7 7                    ",
  949.                 "               7 7 7 7                    ",
  950.                 "               77   7                     ",
  951.                 "               7 7  7                     ",
  952.                 "    bb  bb     777  7      999 999        ",
  953.                 "b   b b b b 99         999 9 9  9  999    ",
  954.                 "b   b b b b 9  999 999 9 9 9 9  9  9   999",
  955.                 "b   b b b b 99 9    9  99  9 9  9  99  9 9",
  956.                 "b   bb  bb  9  999  9  9 9 999 999 9   99 ",
  957.                 "bbb         99   9  9  9 9         999 9 9",
  958.                 "               999  9                  9 9",
  959.             },
  960.         }
  961.     }
  962. end
  963.  
  964. for k,v in pairs(images) do
  965.     -- give them easy-to-access x and y sizes
  966.     v.x = #v[1][1]
  967.     v.y = #v[1]
  968.     -- fix white artifacting that occurs due to " " correlating to WHITE in term.blit
  969.     for y = 1, v.y do
  970.         for x = 1, v.x do
  971.             if v[2][y]:sub(x,x) ~= "" and v[3][y]:sub(x,x) ~= "" then
  972.                 if (v[2][y]:sub(x,x) == " " and v[3][y]:sub(x,x) ~= " ") then
  973.                     images[k][2][y] = v[2][y]:sub(1, x - 1) .. initGrid.voidcol .. v[2][y]:sub(x + 1)
  974.                 elseif (v[2][y]:sub(x,x) ~= " " and v[3][y]:sub(x,x) == " ") then
  975.                     images[k][3][y] = v[3][y]:sub(1, x - 1) .. initGrid.voidcol .. v[3][y]:sub(x + 1)
  976.                 end
  977.             end
  978.         end
  979.     end
  980. end
  981.  
  982. local drawImage = function(im, x, y)
  983.     local cx, cy = termgetCursorPos()
  984.     termsetBackgroundColor( tocolors[initGrid.voidcol] )
  985.     termsetTextColor(       tocolors[initGrid.voidcol] )
  986.     for iy = 1, #im[1] do
  987.         for ix = 1, #im[1][iy] do
  988.             termsetCursorPos(x+(ix-1),y+(iy-1))
  989.             if not (im[2][iy]:sub(ix,ix) == " " and im[3][iy]:sub(ix,ix) == " ") then
  990.                 termblit(
  991.                     im[1][iy]:sub(ix,ix),
  992.                     im[2][iy]:sub(ix,ix):gsub("[ f]",initGrid.voidcol),
  993.                     im[3][iy]:sub(ix,ix):gsub("[ f]",initGrid.voidcol)
  994.                 )
  995.             end
  996.         end
  997.     end
  998.     termsetCursorPos(cx,cy)
  999. end
  1000.  
  1001. local deadGuys = {}
  1002. local trail = {}
  1003. local lastTrails = {}
  1004. isPuttingDown = false
  1005.  
  1006. local putTrailXY = function(x, y, p)
  1007.     trail[y] = trail[y] or {}
  1008.     trail[y][x] = {
  1009.         player = p,
  1010.         age = 0
  1011.     }
  1012. end
  1013.  
  1014. local putTrail = function(p)
  1015.     putTrailXY(p.x, p.y, p.num)
  1016. end
  1017.  
  1018. local getTrail = function(x, y)
  1019.     if trail[y] then
  1020.         if trail[y][x] then
  1021.             return player[trail[y][x].player].char, player[trail[y][x].player].color, trail[y][x].age
  1022.         end
  1023.     end
  1024.     return false
  1025. end
  1026.  
  1027. local ageTrails = function()
  1028.     for y,l in pairs(trail) do
  1029.         for x,v in pairs(l) do
  1030.             trail[y][x].age = trail[y][x].age + 1
  1031.         end
  1032.     end
  1033. end
  1034.  
  1035. local control, revControl = {
  1036.     up = keys.up,
  1037.     down = keys.down,
  1038.     left = keys.left,
  1039.     right = keys.right,
  1040.     lookUp = keys.w,
  1041.     lookDown = keys.s,
  1042.     lookLeft = keys.a,
  1043.     lookRight = keys.d,
  1044.     release = keys.space
  1045. }, {}
  1046. for k,v in pairs(control) do
  1047.     revControl[v] = k
  1048. end
  1049.  
  1050. gridFore, gridBack = table.unpack(gridList[gridID])
  1051.  
  1052. local dirArrow = {
  1053.     [-1] = "^",
  1054.     [0] = ">",
  1055.     [1] = "V",
  1056.     [2] = "<"
  1057. }
  1058.  
  1059. local doesIntersectBorder = function(x, y)
  1060.     return mathfloor(x) == grid.x1 or mathfloor(x) == grid.x2 or mathfloor(y) == grid.y1 or mathfloor(y) == grid.y2
  1061. end
  1062.  
  1063. --draws grid and background at scroll 'x' and 'y', along with trails and players
  1064. local drawGrid = function(x, y, onlyDrawGrid, useSetVisible)
  1065.     tsv(false)
  1066.     x, y = mathfloor(x + 0.5), mathfloor(y + 0.5)
  1067.     local bg = {{},{},{}}
  1068.     local foreX, foreY
  1069.     local backX, backY
  1070.     local adjX, adjY
  1071.     local trailChar, trailColor, trailAge, isPlayer, isPredict
  1072.     for sy = 1, scr_y do
  1073.         bg[1][sy] = ""
  1074.         bg[2][sy] = ""
  1075.         bg[3][sy] = ""
  1076.         for sx = 1, scr_x do
  1077.             adjX = (sx + x)
  1078.             adjY = (sy + y)
  1079.             foreX = 1 + (sx + x) % #gridFore[1]
  1080.             foreY = 1 + (sy + y) % #gridFore
  1081.             backX = 1 + mathfloor(sx + (x / 2)) % #gridBack[1]
  1082.             backY = 1 + mathfloor(sy + (y / 2)) % #gridBack
  1083.             trailChar, trailColor, trailAge = getTrail(adjX, adjY)
  1084.             isPlayer = false
  1085.             isPredict = false
  1086.             if not onlyDrawGrid then
  1087.                 for i = 1, #player do
  1088.                     if player[i].x == adjX and player[i].y == adjY then
  1089.                         isPlayer = i
  1090.                         break
  1091.                     elseif (not isHost) and useSkynet and i == you and (
  1092.                         adjX == math.floor(player[i].x + (0.02 * round(ping, 0)) * math.cos(math.rad(player[i].direction * 90))) and
  1093.                         adjY == math.floor(player[i].y + (0.02 * round(ping, 0)) * math.sin(math.rad(player[i].direction * 90)))
  1094.                     ) then
  1095.                         isPredict = i
  1096.                         break
  1097.                     end
  1098.                 end
  1099.             end
  1100.             if isPlayer and (not onlyDrawGrid) and (not doesIntersectBorder(adjX, adjY)) then
  1101.                 bg[1][sy] = bg[1][sy] .. dirArrow[player[isPlayer].direction]
  1102.                 bg[2][sy] = bg[2][sy] .. toblit[player[isPlayer].color[1]]
  1103.                 bg[3][sy] = bg[3][sy] .. grid.voidcol
  1104.             elseif isPredict and (not onlyDrawGrid) and (not doesIntersectBorder(adjX, adjY)) then
  1105.                 bg[1][sy] = bg[1][sy] .. "o"
  1106.                 bg[2][sy] = bg[2][sy] .. grid.forecol
  1107.                 bg[3][sy] = bg[3][sy] .. grid.voidcol
  1108.             else
  1109.                 if (not onlyDrawGrid) and trailChar and trailColor then
  1110.                     trailColor = trailColor[1 + ((trailAge - 1) % #trailColor)]
  1111.                     bg[1][sy] = bg[1][sy] .. trailChar
  1112.                     bg[2][sy] = bg[2][sy] .. toblit[trailColor]
  1113.                     bg[3][sy] = bg[3][sy] .. grid.voidcol
  1114.                 else
  1115.                     if (not onlyDrawGrid) and (adjX < grid.x1 or adjX > grid.x2 or adjY < grid.y1 or adjY > grid.y2) then
  1116.                         bg[1][sy] = bg[1][sy] .. " "
  1117.                         bg[2][sy] = bg[2][sy] .. grid.voidcol
  1118.                         bg[3][sy] = bg[3][sy] .. grid.voidcol
  1119.                     elseif (not onlyDrawGrid) and doesIntersectBorder(adjX, adjY) then
  1120.                         bg[1][sy] = bg[1][sy] .. grid.border
  1121.                         bg[2][sy] = bg[2][sy] .. grid.voidcol
  1122.                         bg[3][sy] = bg[3][sy] .. grid.edgecol
  1123.                     else
  1124.                         if gridFore[foreY]:sub(foreX,foreX) ~= " " then
  1125.                             bg[1][sy] = bg[1][sy] .. gridFore[foreY]:sub(foreX,foreX)
  1126.                             bg[2][sy] = bg[2][sy] .. grid.forecol
  1127.                             bg[3][sy] = bg[3][sy] .. grid.voidcol
  1128.                         elseif gridBack[backY]:sub(backX,backX) ~= " " then
  1129.                             bg[1][sy] = bg[1][sy] .. gridBack[backY]:sub(backX,backX)
  1130.                             bg[2][sy] = bg[2][sy] .. grid.backcol
  1131.                             bg[3][sy] = bg[3][sy] .. grid.voidcol
  1132.                         else
  1133.                             bg[1][sy] = bg[1][sy] .. " "
  1134.                             bg[2][sy] = bg[2][sy] .. grid.voidcol
  1135.                             bg[3][sy] = bg[3][sy] .. grid.voidcol
  1136.                         end
  1137.                     end
  1138.                 end
  1139.             end
  1140.         end
  1141.     end
  1142.     for sy = 1, scr_y do
  1143.         termsetCursorPos(1,sy)
  1144.         termblit(
  1145.             bg[1][sy],
  1146.             bg[2][sy],
  1147.             bg[3][sy]
  1148.         )
  1149.     end
  1150.     if doDrawPlayerNames and (not onlyDrawGrid) then
  1151.         for i = 1, #player do
  1152.             if doRenderOwnName or (i ~= you) then
  1153.                 termsetTextColor(player[i].color[1])
  1154.                 adjX = mathfloor(player[i].x - (scrollX + scrollAdjX) - (#player[i].name / 2) + 1)
  1155.                 adjY = mathfloor(player[i].y - (scrollY + scrollAdjY) - 1.5)
  1156.                 for cx = adjX, adjX + #player[i].name do
  1157.                     if doesIntersectBorder(adjX + mathfloor(0.5 + scrollX + scrollAdjX), adjY + mathfloor(0.5 + scrollY + scrollAdjY)) then
  1158.                         termsetBackgroundColor(tocolors[grid.edgecol])
  1159.                     else
  1160.                         termsetBackgroundColor(tocolors[grid.voidcol])
  1161.                     end
  1162.                     termsetCursorPos(cx, adjY)
  1163.                     termwrite(player[i].name:sub(cx-adjX+1, cx-adjX+1))
  1164.                 end
  1165.             end
  1166.         end
  1167.     end
  1168.     tsv(true)
  1169. end
  1170.  
  1171. local getTime = function()
  1172.     if os.epoch then
  1173.         return os.epoch("utc")
  1174.     else
  1175.         return 24 * os.day() + os.time()
  1176.     end
  1177. end
  1178.  
  1179. local render = function(useSetVisible, netTime)
  1180.     local p = player[you]
  1181.     drawGrid(scrollX + scrollAdjX, scrollY + scrollAdjY, false, useSetVisible)
  1182.     termsetCursorPos(1,1)
  1183.     termsetTextColor(player[you].color[1])
  1184.     termsetBackgroundColor(tocolors[grid.voidcol])
  1185.     term.write("P" .. you)
  1186.     term.setTextColor(colors.white)
  1187.  
  1188.     for x = 0, p.trailMax - 1 do
  1189.         if not (x - p.trailLevel >= -0.4) then
  1190.             if (x - p.trailLevel) > -0.7 then
  1191.                 term.setTextColor(colors.gray)
  1192.                 term.write("@")
  1193.             elseif (x - p.trailLevel) > -1 then
  1194.                 term.setTextColor(colors.lightGray)
  1195.                 term.write("@")
  1196.             else
  1197.                 term.setTextColor(colors.white)
  1198.                 term.write("@")
  1199.             end
  1200.         end
  1201.     end
  1202.     term.setCursorPos(1,2)
  1203.     if netTime and useSkynet then
  1204.         ping = (getTime() - netTime)
  1205.         term.setTextColor(colors.white)
  1206.         term.write(" " .. tostring(ping) .. " ms")
  1207.     end
  1208.     term.setTextColor(colors.white)
  1209. end
  1210.  
  1211. local pleaseWait = function()
  1212.     local periods = 1
  1213.     local maxPeriods = 5
  1214.     termsetBackgroundColor(colors.black)
  1215.     termsetTextColor(colors.gray)
  1216.     termclear()
  1217.  
  1218.     local tID = os.startTimer(0.2)
  1219.     local evt, txt
  1220.     if useSkynet then
  1221.         txt = "Waiting for Skynet game"
  1222.     else
  1223.         txt = "Waiting for modem game"
  1224.     end
  1225.  
  1226.     while true do
  1227.         cwrite("(Press 'Q' to cancel)", 2)
  1228.         cwrite(txt, scr_y - 2, maxPeriods)
  1229.         termwrite(("."):rep(periods))
  1230.         evt = {os.pullEvent()}
  1231.         if evt[1] == "timer" and evt[2] == tID then
  1232.             tID = os.startTimer(0.5)
  1233.             periods = (periods % maxPeriods) + 1
  1234.             term.clearLine()
  1235.         elseif evt[1] == "key" and evt[2] == keys.q then
  1236.             return
  1237.         end
  1238.     end
  1239. end
  1240.  
  1241. local startCountdown = function()
  1242.     local cName = "PLAYER " .. you
  1243.     local col = colors.white
  1244.     for k,v in pairs(colors) do
  1245.         if player[you].color[1] == v then
  1246.             cName = k:upper()
  1247.             col = v
  1248.             break
  1249.         end
  1250.     end
  1251.     local cMessage = "You are "
  1252.     scrollX = player[you].x - mathfloor(scr_x / 2)
  1253.     scrollY = player[you].y - mathfloor(scr_y / 2)
  1254.     for i = 3, 1, -1 do
  1255.         render(true)
  1256.         termsetTextColor(colors.white)
  1257.         for x = 1, #cMessage+1 do
  1258.             termsetCursorPos(-1 + x + mathfloor(scr_x / 2 - (#cMessage + #cName) / 2), mathfloor(scr_y / 2) + 2)
  1259.             if cMessage:sub(x,x) ~= " " and x <= #cMessage then
  1260.                 termwrite(cMessage:sub(x,x))
  1261.             end
  1262.         end
  1263.         termsetTextColor(col)
  1264.         termwrite(player[you].name)
  1265.         termsetTextColor(colors.white)
  1266.         termsetCursorPos(mathfloor(scr_x / 2 - 2), mathfloor(scr_y / 2) + 4)
  1267.         termwrite(i .. "...")
  1268.         sleep(1)
  1269.     end
  1270. end
  1271.  
  1272. local makeMenu = function(x, fromX, y, options, doAnimate, scrollInfo, _cpos)
  1273.     local cpos = _cpos or 1
  1274.     local xmod = 0
  1275.     local cursor = "> "
  1276.     local gsX, gsY = (scrollInfo or {})[2] or 0, (scrollInfo or {})[3] or 0
  1277.     local step = (scrollInfo or {})[1] or 0
  1278.     local lastPos = cpos
  1279.     local image
  1280.     if not doAnimate then
  1281.         drawImage(images.logo, mathceil(scr_x / 2 - images.logo.x / 2), 2)
  1282.         if useSkynet then
  1283.             term.setTextColor(colors.lightGray)
  1284.             cwrite("Skynet Enabled", 2 + images.logo.y)
  1285.         end
  1286.     end
  1287.     local rend = function()
  1288.         if (step % 150 > 100) and doShowByImage then
  1289.             image = images.ldd
  1290.         else
  1291.             image = images.logo
  1292.         end
  1293.         if doAnimate then
  1294.             drawImage(
  1295.                 image,
  1296.                 mathceil(scr_x / 2 - image.x / 2),
  1297.                 2
  1298.             )
  1299.             if useSkynet then
  1300.                 term.setTextColor(colors.lightGray)
  1301.                 cwrite("Skynet Enabled", 2 + image.y)
  1302.             end
  1303.         end
  1304.         for i = 1, #options do
  1305.             if i == cpos then
  1306.                 termsetCursorPos(fromX + xmod, y + (i - 1))
  1307.                 termsetTextColor(colors.white)
  1308.                 termwrite(cursor .. options[i])
  1309.             else
  1310.                 if i == lastPos then
  1311.                     termsetCursorPos(fromX + xmod, y + (i - 1))
  1312.                     termwrite((" "):rep(#cursor))
  1313.                     lastPos = nil
  1314.                 else
  1315.                     termsetCursorPos(fromX + xmod + #cursor, y + (i - 1))
  1316.                 end
  1317.                 termsetTextColor(colors.gray)
  1318.                 termwrite(options[i])
  1319.             end
  1320.         end
  1321.     end
  1322.     local gstID, evt = mathrandom(1,65535)
  1323.     if doAnimate then
  1324.         os.queueEvent("timer", gstID)
  1325.     end
  1326.     rend()
  1327.     local tID = os.startTimer(0.05)
  1328.     while true do
  1329.         evt = {os.pullEvent()}
  1330.         if evt[1] == "key" then
  1331.             if evt[2] == keys.up then
  1332.                 lastPos = cpos
  1333.                 cpos = (cpos - 2) % #options + 1
  1334.             elseif evt[2] == keys.down then
  1335.                 lastPos = cpos
  1336.                 cpos = (cpos % #options) + 1
  1337.             elseif evt[2] == keys.home then
  1338.                 lastPos = cpos
  1339.                 cpos = 1
  1340.             elseif evt[2] == keys["end"] then
  1341.                 lastPos = cpos
  1342.                 cpos = #options
  1343.             elseif evt[2] == keys.enter then
  1344.                 return cpos, {step, gsX, gsY}
  1345.             end
  1346.         elseif evt[1] == "mouse_click" then
  1347.             if evt[4] >= y and evt[4] < y+#options then
  1348.                 if cpos == evt[4] - (y - 1) then
  1349.                     return cpos, {step, gsX, gsY}
  1350.                 else
  1351.                     cpos = evt[4] - (y - 1)
  1352.                     doRend = true
  1353.                 end
  1354.             end
  1355.         elseif evt[1] == "timer" then
  1356.             if evt[2] == gstID then
  1357.                 gstID = os.startTimer(gameDelayInit)
  1358.                 drawGrid(gsX, gsY, true)
  1359.                 step = step + 1
  1360.                 if mathceil(step / 100) % 2 == 1 then
  1361.                     gsX = gsX + 1
  1362.                 else
  1363.                     gsY = gsY - 1
  1364.                 end
  1365.                 doRend = true
  1366.             elseif evt[2] == tID then
  1367.                 if x > fromX and xmod < x - fromX then
  1368.                     xmod = math.min(xmod + 1, x - fromX)
  1369.                     drawGrid(gsX, gsY, true)
  1370.                     tID = os.startTimer(0.05)
  1371.                 elseif xmod > x - fromX then
  1372.                     xmod = math.max(xmod - 1, x - fromX)
  1373.                     drawGrid(gsX, gsY, true)
  1374.                     tID = os.startTimer(0.05)
  1375.                 end
  1376.                 doRend = true
  1377.             end
  1378.         end
  1379.         if lastPos ~= cpos or doRend then
  1380.             rend()
  1381.             doRend = false
  1382.         end
  1383.     end
  1384. end
  1385.  
  1386. local specialRead = function(scrollInfo, specialNames, message, preInput)
  1387.     specialNames = specialNames or {}
  1388.     local gsX, gsY = (scrollInfo or {})[2] or 0, (scrollInfo or {})[3] or 0
  1389.     local step = (scrollInfo or {})[1] or 0
  1390.     local tID = os.startTimer(gameDelayInit)
  1391.     local buff = {}
  1392.     local cpos = 1
  1393.     local maxSize = 15
  1394.     local evt
  1395.     for x = 1, #preInput do
  1396.         buff[x] = preInput:sub(x, x)
  1397.         cpos = cpos + 1
  1398.     end
  1399.     term.setCursorBlink(true)
  1400.     local rend = function()
  1401.         drawGrid(gsX, gsY, true)
  1402.         term.setTextColor(colors.white)
  1403.         cwrite(message, scr_y - 5)
  1404.         term.setTextColor(specialNames[table.concat(buff):lower()] or colors.white)
  1405.         term.setCursorPos( cwrite(table.concat(buff), scr_y - 3, nil, cpos) - 1, scr_y - 3)
  1406.         term.setTextColor(colors.white)
  1407.     end
  1408.     while true do
  1409.         evt = {os.pullEvent()}
  1410.         if evt[1] == "timer" and evt[2] == tID then
  1411.             -- render the bg
  1412.             tID = os.startTimer(gameDelayInit)
  1413.             step = step + 1
  1414.             if mathceil(step / 100) % 2 == 1 then
  1415.                 gsX = gsX + 1
  1416.             else
  1417.                 gsY = gsY - 1
  1418.             end
  1419.             rend()
  1420.         elseif evt[1] == "char" then
  1421.             if #buff < maxSize then
  1422.                 table.insert(buff, cpos, evt[2])
  1423.                 cpos = cpos + 1
  1424.                 rend()
  1425.             end
  1426.         elseif evt[1] == "key" then
  1427.             if evt[2] == keys.left then
  1428.                 cpos = math.max(1, cpos - 1)
  1429.             elseif evt[2] == keys.right then
  1430.                 cpos = math.min(#buff + 1, cpos + 1)
  1431.             elseif evt[2] == keys.home then
  1432.                 cpos = 1
  1433.             elseif evt[2] == keys["end"] then
  1434.                 cpos = #buff
  1435.             elseif evt[2] == keys.backspace then
  1436.                 if cpos > 1 then
  1437.                     table.remove(buff, cpos - 1)
  1438.                     cpos = cpos - 1
  1439.                     rend()
  1440.                 end
  1441.             elseif evt[2] == keys.delete then
  1442.                 if buff[cpos] then
  1443.                     table.remove(buff, cpos)
  1444.                     rend()
  1445.                 end
  1446.             elseif evt[2] == keys.enter then
  1447.                 term.setCursorBlink(false)
  1448.                 return table.concat(buff), {step, gsX, gsY}
  1449.             end
  1450.         end
  1451.     end
  1452. end
  1453.  
  1454. local passwordChange = function(scrollInfo)
  1455.     return specialRead(scrollInfo, {}, "Enter a password.", argumentPassword or "") or ""
  1456. end
  1457.  
  1458. local nameChange = function(scrollInfo)
  1459.     -- this has no functional significance. just some shoutouts
  1460.     local specialNames = {
  1461.         ["blu"] = colors.blue,
  1462.         ["red"] = colors.red,
  1463.         ["ldd"] = colors.orange,
  1464.         ["lddestroier"] = colors.orange,
  1465.         ["hydraz"] = colors.yellow,
  1466.         ["hugeblank"] = colors.orange,
  1467.         ["bagel"] = colors.orange,
  1468.         ["3d6"] = colors.lime,
  1469.         ["lyqyd"] = colors.red,
  1470.         ["squiddev"] = colors.cyan,
  1471.         ["oeed"] = colors.lime,
  1472.         ["dog"] = colors.purple,
  1473.         ["nothy"] = colors.lightGray,
  1474.         ["kepler"] = colors.cyan,
  1475.         ["kepler155c"] = colors.cyan,
  1476.         ["anavrins"] = colors.blue,
  1477.         ["redmatters"] = colors.red,
  1478.         ["fatmanchummy"] = colors.purple,
  1479.         ["crazed"] = colors.lightBlue,
  1480.         ["ape"] = colors.brown,
  1481.         ["everyos"] = colors.red,
  1482.         ["dan200"] = colors.lightGray,
  1483.         ["dantwohundred"] = colors.lightGray,
  1484.         ["lemmmy"] = colors.red,
  1485.         ["yemmel"] = colors.red,
  1486.         ["apemanzilla"] = colors.brown,
  1487.         ["osmarks"] = colors.green,
  1488.         ["gollark"] = colors.green,
  1489.         ["dece"] = colors.cyan,
  1490.         ["hpwebcamable"] = colors.lightGray,
  1491.         ["theoriginalbit"] = colors.blue,
  1492.         ["bombbloke"] = colors.red,
  1493.         ["kingofgamesyami"] = colors.lightBlue,
  1494.         ["pixeltoast"] = colors.lime,
  1495.         ["creator"] = colors.yellow,
  1496.         ["dannysmc"] = colors.purple,
  1497.         ["dannysmc95"] = colors.purple,
  1498.         ["kingdaro"] = colors.blue,
  1499.         ["valithor"] = colors.orange,
  1500.         ["logandark"] = colors.lightGray,
  1501.         ["lupus590"] = colors.lightGray,
  1502.         ["nitrogenfingers"] = colors.green,
  1503.         ["gravityscore"] = colors.lime,
  1504.         ["1lann"] = colors.gray,
  1505.         ["konlab"] = colors.brown,
  1506.         ["elvishjerricco"] = colors.pink
  1507.     }
  1508.     return specialRead(scrollInfo, specialNames, "Enter your name.", argumentName or player[you].initName)
  1509. end
  1510.  
  1511. local titleScreen = function()
  1512.     termclear()
  1513.     local menuOptions, options, choice, scrollInfo
  1514.     if kioskMode then
  1515.         menuOptions = {
  1516.             "Start Game",
  1517.             "How to Play",
  1518.         }
  1519.     else
  1520.         menuOptions = {
  1521.             "Start Game",
  1522.             "How to Play",
  1523.             "Options...",
  1524.             "Exit"
  1525.         }
  1526.     end
  1527.     local currentX = 2
  1528.     while true do
  1529.         choice, scrollInfo = makeMenu(2, currentX, scr_y - #menuOptions, menuOptions, true, scrollInfo)
  1530.         currentX = 2
  1531.         if choice == 1 then
  1532.             return "start"
  1533.         elseif choice == 2 then
  1534.             return "help"
  1535.         elseif choice == 3 then
  1536.             local _cpos
  1537.             while true do
  1538.                 options = {
  1539.                     "Grid Demo",
  1540.                     "Change Name",
  1541.                     "Change Grid",
  1542.                     "Change Password",
  1543.                     (useSkynet and "Disable" or "Enable") .. " Skynet",
  1544.                     "Back..."
  1545.                 }
  1546.                 choice, scrollInfo = makeMenu(8, currentX, scr_y - #options, options, true, scrollInfo, _cpos)
  1547.                 currentX = 8
  1548.                 _cpos = choice
  1549.                 if choice == 1 then
  1550.                     return "demo"
  1551.                 elseif choice == 2 then
  1552.                     local newName = nameChange(scrollInfo)
  1553.                     if #newName > 0 then
  1554.                         if newName:upper() == "BLU" or newName:upper() == "RED" or newName:gsub(" ","") == "" then
  1555.                             argumentName = nil
  1556.                         else
  1557.                             argumentName = newName
  1558.                         end
  1559.                     else
  1560.                         argumentName = nil
  1561.                     end
  1562.                 elseif choice == 3 then
  1563.                     gridID = (gridID % #gridList) + 1
  1564.                     gridFore, gridBack = table.unpack(gridList[gridID])
  1565.                 elseif choice == 4 then
  1566.                     argumentPassword = passwordChange(scrollInfo)
  1567.                 elseif choice == 5 then
  1568.                     if http.websocket then
  1569.                         useSkynet = not useSkynet
  1570.                         setUpModem()
  1571.                         if skynet and not useSkynet then
  1572.                             skynet.socket.close()
  1573.                         end
  1574.                     else
  1575.                         term.clear()
  1576.                         term.setTextColor(colors.white)
  1577.                         cwrite("Alas, this version of CC",  -2 + scr_y / 2)
  1578.                         cwrite("does not support Skynet.",  -1 + scr_y / 2)
  1579.                         term.setTextColor(colors.lightGray)
  1580.                         cwrite("Use CC:Tweaked or CCEmuX",   1 + scr_y / 2)
  1581.                         cwrite("instead for netplay.",       2 + scr_y / 2)
  1582.                         cwrite("Press any key to go back.",  4 + scr_y / 2)
  1583.                         sleep(0.1)
  1584.                         os.pullEvent("key")
  1585.                     end
  1586.                 elseif choice == 6 then
  1587.                     break
  1588.                 end
  1589.             end
  1590.         elseif choice == 4 then
  1591.             return "exit"
  1592.         end
  1593.     end
  1594. end
  1595.  
  1596. local cleanExit = function()
  1597.     termsetBackgroundColor(colors.black)
  1598.     termsetTextColor(colors.white)
  1599.     termclear()
  1600.     cwrite("Thanks for playing!", 2)
  1601.     termsetCursorPos(1, scr_y)
  1602. end
  1603.  
  1604. local parseMouseInput = function(button, x, y, direction)
  1605.     local output = false
  1606.     local cx = x - scr_mx
  1607.     local cy = y - scr_my
  1608.  
  1609.     if useLegacyMouseControl or mode == "demo" then -- outdated mouse input, useful for grid demo though
  1610.         cx = cx * (scr_y / scr_x)
  1611.         if cx > cy then
  1612.             if -cx > cy then
  1613.                 output = "up"
  1614.             else
  1615.                 output = "right"
  1616.             end
  1617.         else
  1618.             if -cx < cy then
  1619.                 output = "down"
  1620.             else
  1621.                 output = "left"
  1622.             end
  1623.         end
  1624.     else
  1625.         cx = cx + scrollAdjX
  1626.         cy = cy + scrollAdjY
  1627.         if button == 1 then -- move player
  1628.             if direction % 2 == 0 then -- moving horizontally
  1629.                 if cy > 0 then
  1630.                     output = "down"
  1631.                 elseif cy < 0 then
  1632.                     output = "up"
  1633.                 end
  1634.             else -- moving vertically
  1635.                 if cx > 0 then
  1636.                     output = "right"
  1637.                 elseif cx < 0 then
  1638.                     output = "left"
  1639.                 end
  1640.             end
  1641.         elseif button == 2 then -- release trail
  1642.             output = "release"
  1643.         end
  1644.     end
  1645.  
  1646.     return control[output]
  1647. end
  1648.  
  1649. local getInput = function()
  1650.     local evt
  1651.     local mkey = -1
  1652.     while true do
  1653.         evt = {os.pullEvent()}
  1654.         if lockInput then
  1655.             keysDown = {}
  1656.             miceDown = {}
  1657.         else
  1658.             if evt[1] == "key" then
  1659.                 if (not keysDown[evt[2]]) and (
  1660.                     evt[2] == control.up or
  1661.                     evt[2] == control.down or
  1662.                     evt[2] == control.left or
  1663.                     evt[2] == control.right
  1664.                 ) then
  1665.                     lastDirectionPressed = revControl[evt[2]]
  1666.                 end
  1667.                 keysDown[evt[2]] = true
  1668.             elseif evt[1] == "key_up" then
  1669.                 keysDown[evt[2]] = false
  1670.             elseif evt[1] == "mouse_click" or (useLegacyMouseControl and evt[1] == "mouse_drag") then
  1671.                 if evt[1] == "mouse_drag" then
  1672.                     keysDown[mkey] = false
  1673.                 end
  1674.                 miceDown[evt[2]] = {evt[3], evt[4]}
  1675.                 mkey = parseMouseInput(evt[2], evt[3], evt[4], player[you].direction) or -1
  1676.                 lastDirectionPressed = revControl[mkey]
  1677.                 keysDown[mkey] = true
  1678.             elseif evt[1] == "mouse_drag" then
  1679.                 miceDown[evt[2]] = {evt[3], evt[4]}
  1680.             elseif evt[1] == "mouse_up" then
  1681.                 keysDown[mkey] = false
  1682.                 miceDown[evt[2]] = nil
  1683.                 mkey = parseMouseInput(evt[2], evt[3], evt[4], player[you].direction) or -1
  1684.                 keysDown[mkey] = false
  1685.             end
  1686.         end
  1687.     end
  1688. end
  1689.  
  1690. local scrollToPosition = function(x, y)
  1691.     for i = 1, 16 do
  1692.         scrollX = (scrollX + x - (scr_x/2)) / 2
  1693.         scrollY = (scrollY + y - (scr_y/2)) / 2
  1694.         render(true)
  1695.         sleep(0.05)
  1696.     end
  1697. end
  1698.  
  1699. local gridDemo = function()
  1700.     keysDown = {}
  1701.     miceDown = {}
  1702.     scrollX, scrollY = math.floor(scr_x * -0.5), math.floor(scr_y * -0.75)
  1703.     while true do
  1704.         if keysDown[keys.left] then
  1705.             scrollX = scrollX - 1
  1706.         end
  1707.         if keysDown[keys.right] then
  1708.             scrollX = scrollX + 1
  1709.         end
  1710.         if keysDown[keys.up] then
  1711.             scrollY = scrollY - 1
  1712.         end
  1713.         if keysDown[keys.down] then
  1714.             scrollY = scrollY + 1
  1715.         end
  1716.         if keysDown[keys.q] then
  1717.             return "end"
  1718.         end
  1719.         drawGrid(scrollX, scrollY, false, true)
  1720.         ageTrails()
  1721.         sleep(0.05)
  1722.     end
  1723. end
  1724.  
  1725. local sendInfo = function(gameID, doSendTime)
  1726.     transmit(port, {
  1727.         player = isHost and player or nil,
  1728.         name = player[you].name,
  1729.         putTrail = isPuttingDown,
  1730.         gameID = gameID,
  1731.         time = doSendTime and getTime(),
  1732.         keysDown = isHost and nil or keysDown,
  1733.         trail = isHost and lastTrails or nil,
  1734.         deadGuys = isHost and deadGuys or nil,
  1735.         lastDir = lastDirectionPressed
  1736.     })
  1737. end
  1738.  
  1739. local waitForKey = function(time, blockMouse)
  1740.     sleep(time or 0.5)
  1741.     local evt
  1742.     repeat
  1743.         evt = os.pullEvent()
  1744.     until evt == "key" or ((not blockMouse) and evt == "mouse_click")
  1745. end
  1746.  
  1747. local imageAnim = function(image)
  1748.     while true do
  1749.         drawImage(image, mathceil(scr_x / 2 - image.x / 2), mathfloor(scr_y / 2 - image.y / 2))
  1750.         sleep(0.5)
  1751.         render(true)
  1752.         sleep(0.5)
  1753.     end
  1754. end
  1755.  
  1756. local deadAnimation = function(doSend)
  1757.     for k,v in pairs(deadGuys) do
  1758.         player[k].char = "X"
  1759.         lockInput = true
  1760.     end
  1761.     if doSend then
  1762.         sendInfo(gamename, isHost)
  1763.     end
  1764.     if deadGuys[you] or deadGuys[nou] then
  1765.         termsetTextColor(colors.white)
  1766.         if deadGuys[you] and deadGuys[nou] then
  1767.             os.queueEvent("tron_complete", "tie", isHost, player[nou].name)
  1768.             scrollToPosition(player[nou].x, player[nou].y)
  1769.             scrollToPosition(player[you].x, player[you].y)
  1770.             parallel.waitForAny(function() imageAnim(images.tie) end, waitForKey)
  1771.             return "end"
  1772.         else
  1773.             if deadGuys[you] then
  1774.                 scrollX, scrollY = player[nou].x - scr_x / 2, player[nou].y - scr_y / 2
  1775.                 os.queueEvent("tron_complete", "lose", isHost, player[nou].name)
  1776.                 scrollToPosition(player[you].x, player[you].y)
  1777.                 parallel.waitForAny(function() imageAnim(images.lose) end, waitForKey)
  1778.                 return "end"
  1779.             elseif deadGuys[nou] then
  1780.                 os.queueEvent("tron_complete", "win", isHost, player[nou].name)
  1781.                 scrollToPosition(player[nou].x, player[nou].y)
  1782.                 parallel.waitForAny(function() imageAnim(images.win) end, waitForKey)
  1783.                 return "end"
  1784.             end
  1785.         end
  1786.     end
  1787. end
  1788.  
  1789. local debugMoveMode = false -- only works if host
  1790. local moveTick = function(doSend)
  1791.     local p
  1792.     local hasMoved
  1793.     for i = 1, #player do
  1794.         p = player[i]
  1795.         hasMoved = false
  1796.         if not p.dead then
  1797.             if isHost then
  1798.                 if debugMoveMode then
  1799.                     if (i == 1 and keysDown[control.left]) or (i == 2 and netKeysDown[control.left]) then
  1800.                         p.x = p.x - 1
  1801.                         hasMoved = true
  1802.                     end
  1803.                     if (i == 1 and keysDown[control.right]) or (i == 2 and netKeysDown[control.right]) then
  1804.                         p.x = p.x + 1
  1805.                         hasMoved = true
  1806.                     end
  1807.                     if (i == 1 and keysDown[control.up]) or (i == 2 and netKeysDown[control.up]) then
  1808.                         p.y = p.y - 1
  1809.                         hasMoved = true
  1810.                     end
  1811.                     if (i == 1 and keysDown[control.down]) or (i == 2 and netKeysDown[control.down]) then
  1812.                         p.y = p.y + 1
  1813.                         hasMoved = true
  1814.                     end
  1815.                 else
  1816.                     p.x = p.x + mathfloor(mathcos(mathrad(p.direction * 90)))
  1817.                     p.y = p.y + mathfloor(mathsin(mathrad(p.direction * 90)))
  1818.                     hasMoved = true
  1819.                 end
  1820.                 if hasMoved and (doesIntersectBorder(p.x, p.y) or getTrail(p.x, p.y)) then
  1821.                     p.dead = true
  1822.                     deadGuys[i] = true
  1823.                 else
  1824.                     if p.putTrail or (p.trailLevel < 1) then
  1825.                         if hasMoved then
  1826.                             putTrail(p)
  1827.                             lastTrails[#lastTrails+1] = {p.x, p.y, p.num}
  1828.                             if #lastTrails > #player then
  1829.                                 tableremove(lastTrails, 1)
  1830.                             end
  1831.                         end
  1832.                         if p.putTrail then
  1833.                             p.trailLevel = math.min(p.trailLevel + p.trailRegen, p.trailMax)
  1834.                         else
  1835.                             p.trailLevel = math.max(p.trailLevel - 1, 0)
  1836.                         end
  1837.                     else
  1838.                         p.trailLevel = math.max(p.trailLevel - 1, 0)
  1839.                     end
  1840.                 end
  1841.             end
  1842.             for a = 1, #player do
  1843.                 if (a ~= i) and (player[a].x == p.x and player[a].y == p.y) then
  1844.                     p.dead = true
  1845.                     deadGuys[i] = true
  1846.                     if (p.direction + 2) % 4 == player[a].direction % 4 then
  1847.                         player[a].dead = true
  1848.                         deadGuys[a] = true
  1849.                     end
  1850.                     break
  1851.                 end
  1852.             end
  1853.         end
  1854.     end
  1855.     return deadAnimation(doSend)
  1856. end
  1857.  
  1858. local setDirection = function(p, checkDir, lastDir)
  1859.     if (lastDir == control.left) and (checkDir or p.direction) ~= 0 then
  1860.         p.direction = 2
  1861.         return true
  1862.     elseif (lastDir == control.right) and (checkDir or p.direction) ~= 2 then
  1863.         p.direction = 0
  1864.         return true
  1865.     elseif (lastDir == control.up) and (checkDir or p.direction) ~= 1 then
  1866.         p.direction = -1
  1867.         return true
  1868.     elseif (lastDir == control.down) and (checkDir or p.direction) ~= -1 then
  1869.         p.direction = 1
  1870.         return true
  1871.     elseif isPuttingDown == keysDown[control.release] then
  1872.         return true
  1873.     else
  1874.         return false
  1875.     end
  1876. end
  1877.  
  1878. local game = function()
  1879.     local outcome
  1880.     local p, np, timeoutID, tID, evt, netTime
  1881.     while true do
  1882.         netTime = nil
  1883.         if isHost then
  1884.             sleep(gameDelay)
  1885.         else
  1886.             timeoutID = os.startTimer(3)
  1887.             repeat
  1888.                 evt, tID = os.pullEvent()
  1889.             until evt == "move_tick" or (evt == "timer" and tID == timeoutID)
  1890.             if evt == "timer" then
  1891.                 os.queueEvent("tron_complete", "timeout", isHost, player[nou].name)
  1892.                 parallel.waitForAny(function() imageAnim(images.timeout) end, waitForKey)
  1893.                 return
  1894.             elseif evt == "move_tick" then
  1895.                 netTime = tID
  1896.             end
  1897.         end
  1898.         p  = player[you]
  1899.         np = player[nou]
  1900.  
  1901.         if isHost then
  1902.             setDirection(p, nil, control[lastDirectionPressed])
  1903.             setDirection(np, nil, control[netLastDirectionPressed])
  1904.             p.putTrail = not keysDown[control.release]
  1905.         else
  1906.             setDirection(p, nil, control[lastDirectionPressed])
  1907.             isPuttingDown = not keysDown[control.release]
  1908.             sendInfo(gamename, isHost)
  1909.         end
  1910.  
  1911.         if miceDown[3] then
  1912.             scrollAdjX = scrollAdjX + (miceDown[3][1] - scr_x / 2) / (scr_x / 4)
  1913.             scrollAdjY = scrollAdjY + (miceDown[3][2] - scr_y / 2) / (scr_y / 2.795)
  1914.         else
  1915.             if keysDown[control.lookLeft] then
  1916.                 scrollAdjX = scrollAdjX - 2
  1917.             end
  1918.             if keysDown[control.lookRight] then
  1919.                 scrollAdjX = scrollAdjX + 2
  1920.             end
  1921.             if keysDown[control.lookUp] then
  1922.                 scrollAdjY = scrollAdjY - 1.25
  1923.             end
  1924.             if keysDown[control.lookDown] then
  1925.                 scrollAdjY = scrollAdjY + 1.25
  1926.             end
  1927.         end
  1928.  
  1929.         scrollAdjX = scrollAdjX * 0.8
  1930.         scrollAdjY = scrollAdjY * 0.8
  1931.  
  1932.         if isHost then
  1933.             outcome = moveTick(true)
  1934.         else
  1935.             outcome = deadAnimation(false)
  1936.         end
  1937.         ageTrails()
  1938.         if outcome == "end" then
  1939.             return
  1940.         else
  1941.             scrollX = p.x - mathfloor(scr_x / 2)
  1942.             scrollY = p.y - mathfloor(scr_y / 2)
  1943.             render(true, (not isHost) and netTime)
  1944.         end
  1945.     end
  1946. end
  1947.  
  1948. local cTime -- current UTC time when looking for game
  1949. local networking = function()
  1950.     local evt, side, channel, repchannel, msg, distance
  1951.     while true do
  1952.         --[[
  1953.         if useSkynet then
  1954.             evt, channel, msg = os.pullEvent("skynet_message")
  1955.         else
  1956.             evt, side, channel, repchannel, msg, distance = os.pullEvent("modem_message")
  1957.         end
  1958.         --]]
  1959.         msg, channel = disknet.receive(channel)
  1960.         if channel == port and type(msg) == "table" then
  1961.             if type(msg.gameID) == "string" then
  1962.                 if waitingForGame and (type(msg.time) == "number") then
  1963.                     if msg.password == argumentPassword or (argumentPassword == "" and not msg.password) then
  1964.  
  1965.                         -- called while waiting for match
  1966.                         if msg.time < cTime then
  1967.                             isHost = false
  1968.                             you, nou = nou, you
  1969.                             gamename = msg.gameID
  1970.                             gameDelay = tonumber(msg.gameDelay) or gameDelayInit
  1971.                             grid = msg.grid or copyTable(initGrid)
  1972.                             player = msg.player or player
  1973.                             player[you].name = argumentName or player[you].initName
  1974.                         else
  1975.                             isHost = true
  1976.                         end
  1977.  
  1978.                         player[nou].name = msg.name or player[nou].initName
  1979.  
  1980.                         transmit(port, {
  1981.                             player = player,
  1982.                             gameID = gamename,
  1983.                             time = cTime,
  1984.                             name = argumentName,
  1985.                             password = argumentPassword,
  1986.                             grid = initGrid
  1987.                         })
  1988.                         waitingForGame = false
  1989.                         netKeysDown = {}
  1990.                         os.queueEvent("new_game", gameID)
  1991.                         return gameID
  1992.                     end
  1993.  
  1994.                 elseif msg.gameID == gamename then
  1995.  
  1996.                     -- called during gameplay
  1997.                     if not isHost then
  1998.                         if type(msg.player) == "table" then
  1999.                             player[nou].name = msg.name or player[nou].name
  2000.                             player = msg.player
  2001.                             if msg.trail then
  2002.                                 for i = 1, #msg.trail do
  2003.                                     putTrailXY(table.unpack(msg.trail[i]))
  2004.                                 end
  2005.                             end
  2006.                             deadGuys = msg.deadGuys
  2007.                             os.queueEvent("move_tick", msg.time)
  2008.                         end
  2009.                     elseif type(msg.keysDown) == "table" then
  2010.                         netKeysDown = msg.keysDown
  2011.                         netLastDirectionPressed = msg.lastDir
  2012.                         player[nou].putTrail = msg.putTrail
  2013.                         player[nou].name = msg.name or "???" --player[nou].name
  2014.                     end
  2015.  
  2016.                 end
  2017.             end
  2018.         end
  2019.     end
  2020. end
  2021.  
  2022. local helpScreen = function()
  2023.     termsetBackgroundColor(colors.black)
  2024.     termsetTextColor(colors.white)
  2025.     termclear()
  2026.     termsetCursorPos(1,2)
  2027.     print([[
  2028.     Move your lightcycle with WASD
  2029.      or by tapping left click.
  2030.  
  2031.     Pan the camera with arrows
  2032.      or by holding middle click.
  2033.  
  2034.     Release the trail with spacebar
  2035.      or by holding right click.
  2036.  
  2037.     If you're P2 (red), a gray circle
  2038.     will indicate where you'll turn,
  2039.     to help with Skynet's netlag.
  2040.  
  2041.     Press any key to go back.
  2042.     ]])
  2043.     waitForKey(0.25)
  2044. end
  2045.  
  2046. local startGame = function()
  2047.     -- reset all info between games
  2048.     keysDown = {}
  2049.     miceDown = {}
  2050.     scrollAdjX = 0
  2051.     scrollAdjY = 0
  2052.  
  2053.     trail = {}
  2054.     deadGuys = {}
  2055.     lastDirectionPressed = nil
  2056.     netLastDirectionPressed = nil
  2057.     gameDelay = gameDelayInit
  2058.     grid = copyTable(initGrid)
  2059.     player = resetPlayers()
  2060.     you, nou = 1, 2
  2061.     gamename = ""
  2062.     for i = 1, 32 do
  2063.         gamename = gamename .. string.char(mathrandom(1,126))
  2064.     end
  2065.  
  2066.     waitingForGame = true
  2067.     cTime = getTime()
  2068.     transmit(port, {
  2069.         player = player,
  2070.         gameID = gamename,
  2071.         gameDelay = gameDelayInit,
  2072.         time = cTime,
  2073.         password = argumentPassword,
  2074.         name = argumentName,
  2075.         grid = initGrid
  2076.     })
  2077.     rVal = parallel.waitForAny( pleaseWait, networking )
  2078.     sleep(0.1)
  2079.     player[you].name = argumentName or player[you].initName
  2080.     if rVal == 2 then
  2081.         startCountdown()
  2082.         parallel.waitForAny( getInput, game, networking )
  2083.     end
  2084. end
  2085.  
  2086. local decision
  2087.  
  2088. local main = function()
  2089.     return pcall(function()
  2090.         local rVal
  2091.         while true do
  2092.             mode = "menu"
  2093.             decision = titleScreen()
  2094.             lockInput = false
  2095.             if decision == "start" then
  2096.                 mode = "game"
  2097.                 if useSkynet then
  2098.                     parallel.waitForAny(startGame, skynet.listen)
  2099.                 else
  2100.                     startGame()
  2101.                 end
  2102.             elseif decision == "help" then
  2103.                 mode = "help"
  2104.                 helpScreen()
  2105.             elseif decision == "demo" then
  2106.                 mode = "demo"
  2107.                 parallel.waitForAny( getInput, gridDemo )
  2108.             elseif decision == "exit" then
  2109.                 return cleanExit()
  2110.             end
  2111.         end
  2112.     end)
  2113. end
  2114.  
  2115. if doGridDemo then
  2116.     parallel.waitForAny(function()
  2117.         local step, gsX, gsY = 0, 0, 0
  2118.         while true do
  2119.             drawGrid(gsX, gsY, true)
  2120.             step = step + 1
  2121.             if mathceil(step / 100) % 2 == 1 then
  2122.                 gsX = gsX + 1
  2123.             else
  2124.                 gsY = gsY - 1
  2125.             end
  2126.             sleep(0.05)
  2127.         end
  2128.     end, function()
  2129.         sleep(0.1)
  2130.         local evt, key
  2131.         repeat
  2132.             evt, key = os.pullEvent("key")
  2133.         until key == keys.q
  2134.         sleep(0.1)
  2135.     end)
  2136. else
  2137.     if useOnce then
  2138.         term.setCursorBlink(false)
  2139.         if useSkynet then
  2140.             parallel.waitForAny(startGame, skynet.listen)
  2141.             skynet.socket.close()
  2142.         else
  2143.             startGame()
  2144.         end
  2145.         term.setCursorPos(1, scr_y)
  2146.     else
  2147.         main()
  2148.         if skynet then
  2149.             skynet.socket.close()
  2150.         end
  2151.     end
  2152. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement