Advertisement
LDDestroier

MCCI (StateMachine)

Nov 13th, 2017
434
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 18.20 KB | None | 0 0
  1. --[[
  2.   Modular Chatbox Command Interpreter
  3.     Made by LDDestroier
  4.   pastebin get ECeJ3CpL mcci  
  5. --]]
  6. local progname = fs.getName(shell.getRunningProgram())
  7. local baseDir = ".mcci" --all other directories are combined with this one, you see
  8. local commandDir = fs.combine(baseDir,"cmd") --a folder
  9. local commandHelpDir = fs.combine(baseDir,"cmdhelp") --a folder
  10. local chatlogDir = fs.combine(baseDir,"chatlog") --a file
  11. local banDir = fs.combine(baseDir,"banlist")
  12. local adminDir = fs.combine(baseDir,"adminlist")
  13. local configDir = fs.combine(baseDir,"config")
  14. local apiDir = fs.combine(baseDir,"statemachine")
  15. local _
  16.  
  17. local useMoarPeriphs = (peripheral.find("chatbox_admin") or peripheral.find("chatbox") or peripheral.find("chat_box")) and true or false --either moarperipherals/computronics xor peripherals++
  18.  
  19. if not fs.exists(commandDir) then fs.makeDir(commandDir) end
  20. if not fs.exists(commandHelpDir) then fs.makeDir(commandHelpDir) end
  21.  
  22. if not statemachine then
  23.     if fs.exists(apiDir) then
  24.         os.loadAPI(apiDir)
  25.         print("Loaded StateMachine API.")
  26.     else
  27.         print("Downloading StateMachine API...")
  28.         local foyle = http.get("https://pastebin.com/raw/3qe1iUQc")
  29.         if not foyle then
  30.             print("Could not download StateMachine API...")
  31.             return false
  32.         else
  33.             local file = fs.open(apiDir,"w")
  34.             file.write(foyle.readAll())
  35.             file.close()
  36.             os.loadAPI(apiDir)
  37.             print("Loaded StateMachine API.")
  38.         end
  39.     end
  40. end
  41.  
  42. local adminUserTable = { --only one who can use admin commands. default values.
  43.     "EldidiStroyrr",
  44.     "Notch",
  45. }
  46. if pairs ~= _G.pairs then
  47.     pairs = function(tbl)
  48.         if type(tbl) ~= "table" then
  49.             error("expected a table here, but got "..type(tbl))
  50.         else
  51.             return _G.pairs(tbl)
  52.         end
  53.     end
  54. end
  55.  
  56. local doRestart = false
  57. local adminUser = function(u)
  58.     if type(u) ~= "string" then return false end
  59.     for a = 1, #adminUserTable do
  60.         if adminUserTable[a]:lower() == u:lower() then
  61.             return true
  62.         end
  63.     end
  64.     return false
  65. end
  66. --[[
  67. local getEvents = function(...)
  68.     local arg = table.pack(...)
  69.     local output
  70.     while true do
  71.         output = {os.pullEvent()}
  72.         for a = 1, #arg do
  73.             if output[1] == arg[a] then
  74.                 return table.unpack(output)
  75.             end
  76.         end
  77.     end
  78. end
  79. --]]
  80. --here's a more experimental getEvents...
  81. getEvents = function(...)
  82.     local arg, funky, output = table.pack(...), {}
  83.     if #arg <= 1 then
  84.         return os.pullEvent(table.unpack(arg))
  85.     else
  86.         for a = 1, #arg do
  87.             funky[a] = function() output = {os.pullEvent(arg[a])} end
  88.         end
  89.         parallel.waitForAny(table.unpack(funky))
  90.         return table.unpack(output)
  91.     end
  92. end
  93.  
  94. local mcci = {
  95.     prefix = "(>",
  96.     ignoreErrors = true,
  97.     mcciLabel = "MCCI",
  98. }
  99.  
  100. local chatbox
  101. local usingAdminChatbox = false
  102. local chatDelay = 0.1 --seconds. regular chatboxes in P+1 will error if you use them too fast
  103. local chatbox = peripheral.find("chatbox_admin") or peripheral.find("chatbox") or peripheral.find("chatBox") or peripheral.find("chat_box")
  104. local cLabel
  105. local setLabel = function(newLabel)
  106.     cLabel = newLabel
  107.     if chatbox.setLabel then
  108.         chatbox.setLabel(newLabel)
  109.     elseif chatbox.setName then
  110.         chatbox.setName(newLabel)
  111.     end
  112. end
  113. if useMoarPeriphs then setLabel(mcci.mcciLabel) end
  114. local SAY = chatbox.say
  115. local WHISPER = commands.tellraw and function(user,message)
  116.     commands.exec("tellraw "..user..' {"text":"['..cLabel..'] '..message..'"}')
  117. end or chatbox.tell
  118. local LISTEN = function(username,checkPrefix)
  119.     local evt
  120.     local user, message
  121.     while true do
  122.         evt = {getEvents("chat_message","chatbox_command","chat")}
  123.         user, message = evt[3 - (useMoarPeriphs and 0 or 1)], evt[4 - (useMoarPeriphs and 0 or 1)]
  124.         if (user == (username or user)) then
  125.             if checkPrefix then
  126.                 if message:sub(1,#tostring(checkPrefix)) == checkPrefix then
  127.                     message = message:sub(#tostring(checkPrefix)+1)
  128.                     break
  129.                 end
  130.             else
  131.                 break
  132.             end
  133.         end
  134.     end
  135.     return user, message
  136. end
  137.  
  138. local explode = function(div,str)
  139.     if (div=='') then return false end
  140.     local pos,arr = 0,{}
  141.     for st,sp in function() return string.find(str,div,pos,false) end do
  142.         table.insert(arr,string.sub(str,pos,st-1))
  143.         pos = sp + 1
  144.     end
  145.     table.insert(arr,string.sub(str,pos))
  146.     return arr
  147. end
  148.  
  149. local chatlog = {}
  150. local blacklist = {}
  151. local whitelist = {}
  152. local userActions = {}
  153. local userActionNames = {}
  154.  
  155. local addToChatlog = function(user,message)
  156.     if chatlog[1] then
  157.         if chatlog[#chatlog][1] == user and chatlog[#chatlog][2] == message then
  158.             chatlog[#chatlog] = {user,message,chatlog[#chatlog][3]+1}
  159.         else
  160.             chatlog[#chatlog+1] = {user,message,1}
  161.         end
  162.     else
  163.         chatlog[#chatlog+1] = {user,message,1}
  164.     end
  165. end
  166.  
  167. local writeChatlog = function()
  168.     prettyOutput = "("..chatlog[#chatlog][3] or "0"..") <"..chatlog[#chatlog][1].."> "..chatlog[#chatlog][2]
  169.     local file = fs.open(chatlogDir,"a")
  170.     file.writeLine(prettyOutput)
  171.     file.close()
  172. end
  173.  
  174. local saveBanlist = function()
  175.     local file = fs.open(banDir,"w")
  176.     for k,v in pairs(blacklist) do
  177.         file.writeLine(k)
  178.         file.writeLine(v)
  179.         file.writeLine("")
  180.     end
  181.     file.close()
  182. end
  183.  
  184. local loadBanlist = function()
  185.     blacklist = {}
  186.     local file = fs.open(banDir,"r")
  187.     local name,reason = ""
  188.     while name do
  189.         name = file.readLine()
  190.         if name then
  191.             reason = file.readLine()
  192.             file.readLine() --blank space
  193.             blacklist[name] = reason
  194.         end
  195.     end
  196.     file.close()
  197.     return blacklist
  198. end
  199.  
  200. local saveAdminlist = function()
  201.     local file = fs.open(adminDir,"w")
  202.     for a = 1, #adminUserTable do
  203.         file.writeLine(adminUserTable[a])
  204.     end
  205.     file.close()
  206. end
  207.  
  208. local loadAdminlist = function()
  209.     adminUserTable = {}
  210.     local file = fs.open(adminDir,"r")
  211.     local line = ""
  212.     while line do
  213.         line = file.readLine()
  214.         if line then
  215.             adminUserTable[#adminUserTable+1] = line
  216.         end
  217.     end
  218.     file.close()
  219.     return adminUserTable
  220. end
  221.  
  222. saveConfig = function()
  223.     local file = fs.open(configDir,"w")
  224.     file.writeLine("prefix:"..textutils.serialize(mcci.prefix))
  225.     file.writeLine("mcciLabel:"..textutils.serialize(mcci.mcciLabel))
  226.     file.writeLine("ignoreErrors:"..tostring(mcci.ignoreErrors))
  227.     file.close()
  228. end
  229.  
  230. local fixInput = function(input)
  231.     if tonumber(input) then
  232.         return tonumber(input)
  233.     elseif input == "false" then
  234.         return false
  235.     elseif input == "true" then
  236.         return true
  237.     elseif textutils.unserialize(input) then
  238.         return textutils.unserialize(input)
  239.     else
  240.         return tostring(input)
  241.     end
  242. end
  243.  
  244. loadConfig = function()
  245.     local file = fs.open(configDir,"r")
  246.     local line = ""
  247.     while line do
  248.         line = file.readLine()
  249.         if line then
  250.             local name = line:sub(1,line:find(":")-1)
  251.             local value = line:sub(line:find(":")+1)
  252.             value = fixInput(value)
  253.             mcci[name] = value
  254.         end
  255.     end
  256.     file.close()
  257. end
  258.  
  259. local scr_x, scr_y = term.getSize()
  260.  
  261. local render = statemachine.unblock(function()
  262.     term.setTextColor(colors.white)
  263.     term.setBackgroundColor(colors.black)
  264.     term.clear()
  265.     term.setCursorPos(1,1)
  266.     print("("..mcci.mcciLabel.."/Prefix='"..mcci.prefix.."')")
  267.     print("(ignoreErrors="..tostring(mcci.ignoreErrors)..")")
  268.     print(("-"):rep(scr_x))
  269.     print("Active Users:")
  270.     for k,v in pairs(userActions) do
  271.         print("-"..k.." ("..userActionNames[k]..")")
  272.     end
  273. end)
  274.  
  275. local initCommand = function(u,cmd,...)
  276.     local yarg = table.pack(...)
  277.     local golly_G = setmetatable({}, {__index=(_ENV or getfenv())})
  278.     golly_G.chatbox = chatbox
  279.     golly_G.WHISPER = WHISPER
  280.     golly_G.SAY = SAY
  281.     golly_G.LISTEN = LISTEN
  282.     golly_G._USERNAME = u
  283.     golly_G._PREFIX = mcci.prefix
  284.     golly_G._ADMIN = adminUser(u)
  285.     golly_G.pairs = pairs
  286.     userActions[u] = statemachine.unblock(function()
  287.         local func = loadfile(fs.combine(commandDir,cmd))
  288.         func = setfenv(func, golly_G)
  289.         local output
  290.         if mcci.ignoreErrors then
  291.             output = {pcall( function() return func(table.unpack(yarg)) end )}
  292.         else
  293.             output = func(table.unpack(yarg))
  294.         end
  295.         return table.unpack(output)
  296.     end)
  297.     userActionNames[u] = cmd
  298.     render()
  299. end
  300.  
  301. local dCommands,dCommandsHelp
  302. dCommandsHelp = {
  303.     ["belay"] = mcci.prefix.."belay [playername] ; Belays all commands or a specific player's.",
  304.     ["ban"] = mcci.prefix.."ban playername ; Bans a player from using this chat command interpreter.",
  305.     ["unban"] = mcci.prefix.."unban playername ; Unbans a player who was banned from using this command interpreter.",
  306.     ["banlist"] = mcci.prefix.."banlist ; Lists every player banned from using this command interpreter.",
  307.     ["help"] = mcci.prefix.."help [commandname] ; Gives a more detailed description of a command.",
  308.     ["update"] = mcci.prefix.."update ; Redownloads the MCCI program and overwrites the source if it's different.",
  309.     ["restart"] = mcci.prefix.."restart ; Restarts the program. One would usually do this after updating.",
  310.     ["checkadmin"] = mcci.prefix.."checkadmin [username] ; Without argument, checks if you are an admin. Also can check if another user is an admin.",
  311.     ["admin"] = mcci.prefix.."admin username ; Sets a username as an administrator.",
  312.     ["sudo"] = mcci.prefix.."sudo username command ; Runs a command as a specific user. Can't be used to abdicate.",
  313.     ["abdicate"] = mcci.prefix.."abdicate ; Use with no arguments to tick yourself off the list of admins. Use with care, there's no confirming.",
  314. }
  315. dCommands = { --default commands
  316.     ["belay"] = function(u,username)
  317.         if adminUser(u) then
  318.             if username then
  319.                 if userActions[username] then
  320.                     userActions[username] = nil
  321.                     WHISPER(u,username.."'s command has been belayed.")
  322.                     WHISPER(username,"Your command has been belayed. Ready.")
  323.                     render()
  324.                 else
  325.                     WHISPER(u,"That user isn't executing a cancelable command.")
  326.                 end
  327.             else
  328.                 WHISPER(u,"All commands have been belayed.")
  329.                 for k,v in pairs(userActions) do
  330.                     WHISPER(k,"Your command has been belayed. Ready.")
  331.                 end
  332.                 userActions = {}
  333.                 render()
  334.             end
  335.         else
  336.             WHISPER(k,"You can't do that!")
  337.         end
  338.     end,
  339.     ["ban"] = function(u,baduser,...)
  340.         local arg = table.pack(...)
  341.         if adminUser(u) then
  342.             if adminUser(baduser) then
  343.                 WHISPER(u,"Very funny. You can't ban admins.")
  344.             elseif not baduser then
  345.                 WHISPER(u,"Do "..mcci.prefix.."ban [username]")
  346.             else
  347.                 if blacklist[baduser] then
  348.                     WHISPER(u,"That dude was already banned.")
  349.                 else
  350.                     blacklist[baduser] = table.concat(arg," ") or "Unspecified reason."
  351.                     userActions[baduser] = nil
  352.                     userActionNames[baduser] = nil
  353.                     render()
  354.                     WHISPER(u,"'"..baduser.."' has been banned from making commands.")
  355.                     WHISPER(baduser,"You are hereby BANNED from making MCCI commands!")
  356.                 end
  357.             end
  358.         else
  359.             WHISPER(u,"You can't do that!")
  360.         end
  361.     end,
  362.     ["banlist"] = function(u)
  363.         WHISPER(u,"## USERS BANNED FROM THIS CHAT AI ##")
  364.         for k,v in pairs(blacklist) do
  365.             WHISPER(u," * "..k.." ("..v..")")
  366.         end
  367.     end,
  368.     ["unban"] = function(u,baduser)
  369.         if adminUser(u) then
  370.             if adminUser(baduser) then
  371.                 WHISPER(u,"Admins can't be banned to begin with, you dolt.")
  372.             elseif (not baduser) then
  373.                 WHISPER(u,"Do "..mcci.prefix.."unban [username]")
  374.             else
  375.                 if (not blacklist[baduser]) then
  376.                     WHISPER(u,"That dude isn't banned.")
  377.                 else
  378.                     blacklist[baduser] = nil
  379.                     WHISPER(u,"'"..baduser.."' has been unbanned from making commands.")
  380.                     WHISPER(baduser,"You've been unbanned from making commands.")
  381.                 end
  382.             end
  383.         else
  384.             if blacklist[gooduser] then
  385.                 WHISPER(u,"You can't do that!")
  386.             else
  387.                 WHISPER(u,"You couldn't do that even if "..gooduser.." were banned!")
  388.             end
  389.         end
  390.     end,
  391.     ["order"] = function(u)
  392.         WHISPER(u,"What, do I look like a pizzeria to you?")
  393.     end,
  394.     ["help"] = function(u,cmd)
  395.         if cmd then
  396.             if dCommands[cmd] then
  397.                 WHISPER(u,dCommandsHelp[cmd])
  398.             else
  399.                 if not fs.exists(fs.combine(commandDir,cmd)) then
  400.                     WHISPER(u,"That command doesn't exist, internally or externally.")
  401.                 else
  402.                     if fs.exists(fs.combine(commandHelpDir,cmd)) then
  403.                         local file = fs.open(fs.combine(commandHelpDir,cmd),"r")
  404.                         local cont = file.readAll(file)
  405.                         file.close()
  406.                         cont = cont:gsub("$PREFIX",mcci.prefix):gsub("\n"," ; ")
  407.                         WHISPER(u,cont)
  408.                     else
  409.                         WHISPER(u,"That external command does not have a help file.")
  410.                     end
  411.                 end
  412.             end
  413.         else
  414.             local list = {}
  415.             local cmdlist = fs.list(commandDir)
  416.             for k,v in pairs(dCommands) do
  417.                 list[#list+1] = k
  418.             end
  419.             for a = 1, #cmdlist do
  420.                 list[#list+1] = cmdlist[a]
  421.             end
  422.             for a = 1, #list do
  423.                 WHISPER(u,mcci.prefix..list[a])
  424.             end
  425.         end
  426.     end,
  427.     ["update"] = function(u)
  428.         if adminUser(u) then
  429.             WHISPER(u,"Downloading latest version...")
  430.             local foyle = http.get("https://pastebin.com/raw/ECeJ3CpL")
  431.             if foyle then
  432.                 local cont = foyle.readAll()
  433.                 local mccifoyle = fs.open(shell.getRunningProgram(),"r")
  434.                 local mccicont = mccifoyle.readAll()
  435.                 mccifoyle.close()
  436.                 if mccicont == cont then
  437.                     WHISPER(u,"You were using the latest version. Aborting.")
  438.                 else
  439.                     local file = fs.open(shell.getRunningProgram(),"w")
  440.                     file.write(cont)
  441.                     file.close()
  442.                     WHISPER(u,"Update complete. Use "..mcci.prefix.."restart to run the latest version.")
  443.                 end
  444.             end
  445.         else
  446.             WHISPER(u,"Yeah, try that again as an admin, doofus.")
  447.         end
  448.     end,
  449.     ["restart"] = function(u)
  450.         if adminUser(u) then
  451.             doRestart = true
  452.         end
  453.     end,
  454.     ["checkadmin"] = function(u,user)
  455.         if not user then
  456.             if adminUser(u) then
  457.                 WHISPER(u,"You're an admin.")
  458.             else
  459.                 WHISPER(u,"You're decidedly not an admin.")
  460.             end
  461.         else
  462.             if adminUser(user) then
  463.                 WHISPER(u,"'"..user.."' is an admin.")
  464.             else
  465.                 WHISPER(u,"'"..user.."' is decidedly not an admin.")
  466.             end
  467.         end
  468.     end,
  469.     ["admin"] = function(u,user)
  470.         if not user then
  471.             if adminUser(u) then
  472.                 WHISPER(u,"Expected an argument with who you wish to make an admin, dunce.")
  473.             else
  474.                 WHISPER(u,"Only admins can make other people admins, you twat.")
  475.             end
  476.         else
  477.             if adminUser(u) then
  478.                 if adminUser(user) then
  479.                     if user == u then
  480.                         WHISPER(u,"Oh my god, stop it.")
  481.                     else
  482.                         WHISPER(u,"That person is already an admin.")
  483.                     end
  484.                 else
  485.                     table.insert(adminUserTable,user)
  486.                     WHISPER(u,"'"..user.."' is now an admin.")
  487.                 end
  488.             else
  489.                 WHISPER(u,"This is an admin command, lamebrain.")
  490.             end
  491.         end
  492.     end,
  493.     ["abdicate"] = function(u,user)
  494.         if adminUser(u) then
  495.             if user then
  496.                 WHISPER(u,"You can't abdicate another user from their adminship.")
  497.             else
  498.                 for a = 1, #adminUserTable do
  499.                     if adminUserTable[a] == u then
  500.                         table.remove(adminUserTable,a)
  501.                         WHISPER(u,"Lo, you have abdicated the throne of adminship.")
  502.                         return
  503.                     end
  504.                 end
  505.                 WHISPER(u,"That's weird. You weren't on the list, but you still did this command.")
  506.             end
  507.         else
  508.             if user then
  509.                 WHISPER(u,"If you really don't like an admin, don't go complaining to me.")
  510.             else
  511.                 WHISPER(u,"Abdicate from what? Only admins can do this!")
  512.             end
  513.         end
  514.     end,
  515.     ["sudo"] = function(u,user,cmd,...)
  516.         if adminUser(u) then
  517.             if cmd == "abdicate" then
  518.                 WHISPER(u,"You can't use sudo to abdicate people!")
  519.             else
  520.                 if user then
  521.                     if userActions[user] then
  522.                         WHISPER(u,"That user is already in a command.")
  523.                     else
  524.                         if cmd then
  525.                             initCommand(user,cmd,...)
  526.                             WHISPER(u,"Ran '"..cmd.."' as '"..user.."'.")
  527.                         else
  528.                             WHISPER(u,"Sudo requires a second argument for the command.")
  529.                         end
  530.                     end
  531.                 else
  532.                     WHISPER(u,"Sudo requires a first argument for the user.")
  533.                 end
  534.             end
  535.         else
  536.             WHISPER(u,"Sudo is an admin's command!")
  537.         end
  538.     end,
  539. }
  540.  
  541. local handleDcommands = function(u,f,...) --heh heh heh
  542.     local arg = table.pack(...)
  543.     if dCommands[f] then
  544.         return true, dCommands[f](u,table.unpack(arg))
  545.     else
  546.         return false
  547.     end
  548. end
  549.  
  550. local handleNormalCommands = function(u,cmd,...)
  551.     local yarg = table.pack(...)
  552.     local cmdlist = fs.list(commandDir)
  553.     for a = 1, #cmdlist do
  554.         if cmdlist[a] == cmd then
  555.             initCommand(u,cmd,table.unpack(yarg))
  556.             if useMoarPeriphs then setLabel(mcci.mcciLabel..":"..userActionNames[u]) end
  557.             return true
  558.         end
  559.     end
  560.     return false
  561. end
  562.  
  563. local fuckingDoIt = statemachine.unblock(function()
  564.     local user, message, isDcommand, isNormalCommand
  565.     while true do
  566.         user, message = LISTEN()
  567.         sleep(0) --to ensure that chatbox output comes AFTER player chat
  568.         addToChatlog(user,message)
  569.         writeChatlog()
  570.         loadBanlist()
  571.         loadAdminlist()
  572.         loadConfig()
  573.         if useMoarPeriphs then setLabel(mcci.mcciLabel) end
  574.         render()
  575.         if not blacklist[user] then
  576.             if message:sub(1,#mcci.prefix) == mcci.prefix then
  577.                 message = message:sub(#mcci.prefix+1)
  578.                 if userActions[user] then
  579.                     if message == "nvm" then
  580.                         userActions[user] = nil
  581.                         userActionNames[user] = nil
  582.                         WHISPER(user,"Command cancelled. Ready.")
  583.                         render()
  584.                     else
  585.                         if useMoarPeriphs then setLabel(mcci.mcciLabel..":"..userActionNames[user]) end
  586.                         os.queueEvent("followup_command_"..user,message)
  587.                     end
  588.                 else
  589.                     isNormalCommand = handleNormalCommands(user,table.unpack(explode(" ",message)))
  590.                     if not isNormalCommand then
  591.                         isDcommand = handleDcommands(user,table.unpack(explode(" ",message)))
  592.                         if doRestart then
  593.                             return
  594.                         else
  595.                             if not isDcommand then
  596.                                 WHISPER(user,"No such command exists, internally or externally.")
  597.                             end
  598.                         end
  599.                     end
  600.                 end
  601.             end
  602.             saveBanlist()
  603.             saveAdminlist()
  604.             saveConfig()
  605.         end
  606.     end
  607. end)
  608.  
  609. if not fs.exists(adminDir) then
  610.     saveAdminlist()
  611. end
  612. if not fs.exists(banDir) then
  613.     saveBanlist()
  614. end
  615. if not fs.exists(configDir) then
  616.     saveConfig()
  617. end
  618.  
  619. loadAdminlist()
  620. loadBanlist()
  621. loadConfig()
  622.  
  623. render()
  624.  
  625. local rootEvent = {}
  626. local getRootEvent = function()
  627.     rootEvent = {os.pullEvent()}
  628. end
  629.  
  630. --this used to be a function called doUserActions
  631. local doBreak, vres
  632. local grodyList
  633. statemachine.setLoop(function()
  634.     fuckingDoIt()
  635.     getRootEvent()
  636.     local vres
  637.     grodyList = {}
  638.     --if #rootEvent > 0 then os.queueEvent(table.unpack(rootEvent)) end
  639.     for k,v in pairs(userActions) do
  640.         vres = nil
  641.         if v then vres = v() end
  642.         if vres then
  643.             if useMoarPeriphs then setLabel(mcci.mcciLabel) end
  644.             WHISPER(k,"Ready.")
  645.             grodyList[#grodyList+1] = k
  646.         end
  647.     end
  648.     for a = 1, #grodyList do
  649.         userActions[grodyList[a]] = nil
  650.         userActionNames[grodyList[a]] = nil
  651.     end
  652.     render()
  653.     return doRestart
  654. end)
  655. statemachine.run()
  656.  
  657. if doRestart then
  658.     SAY("MCCI Restarting.")
  659.     shell.run(shell.getRunningProgram())
  660. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement