LDDestroier

TRON (ComputerCraft)

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