Chaos_Cash

serverHelper.lua

Mar 15th, 2025 (edited)
65
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 58.59 KB | None | 0 0
  1. chatFunctions = {}
  2. droneFunctions = {}
  3. aboutFunctions = {}
  4.  
  5. -- startup functions -------------
  6.  
  7. function startup()
  8. curVersion = "1.2"
  9. patchNotes = "\n- @about system now shows the pastebin link for the program.\n- With @about ranks you can now see information about the diffrent ranks.\n- Added a notification you get when you rankup.\n- Now there is an \"$\" before every insertion of chat commands to hide the message."
  10.  
  11. systemName = "server helper"
  12.  
  13. mainProgramLink = "qQERbqsa"
  14. messageSenderLink = "FpXUacvK"
  15.  
  16.  
  17.    
  18.  
  19.     if fs.exists(systemName .. "/refuelCoords") then
  20.     local file = fs.open(systemName .. "/refuelCoords","r")
  21.     refuelCoords = {["x"] = tonumber(file.readLine()) ,["y"] = tonumber(file.readLine()), ["z"] = tonumber(file.readLine())}
  22.     file.close()
  23.     else
  24.     term.clear()
  25.     print("x:")
  26.     local x = tonumber(read())
  27.     print("y:")
  28.     local y = tonumber(read())
  29.     print("z:")
  30.     local z = tonumber(read())
  31.     local file = fs.open(systemName .. "/refuelCoords","w")
  32.     file.writeLine(x)
  33.     file.writeLine(y)
  34.     file.writeLine(z)
  35.     file.flush()
  36.     file.close()
  37.     refuelCoords = {["x"] = x ,["y"] = y, ["z"] = z}
  38.     end
  39.  
  40.     if fs.exists(systemName .. "/firstStartupDate") then
  41.     local file = fs.open(systemName .. "/firstStartupDate","r")
  42.     firstStartupDate = file.readLine()
  43.     file.close()
  44.     else
  45.     firstStartupDate = os.date()
  46.     local file = fs.open(systemName .. "/firstStartupDate","w")
  47.     file.write(firstStartupDate)
  48.     file.flush()
  49.     file.close()
  50.     end
  51.  
  52. createFiles()
  53. getPeripherals()
  54.  
  55. onlinePlayers = playerDetector.getOnlinePlayers()
  56.  
  57. scrollmenuLen={}
  58. scrollmenuInfos={}
  59.  
  60. dropdown = {}
  61. dropdown["loaded"] = {}
  62. dropdown["loaded"]["len"] = 0
  63.  
  64.  
  65. givenfeedback = readFolder(programFolderName .. "/givenfeedback")
  66.  
  67.  
  68. playerData = {}
  69.  
  70.  
  71. sendTheseMessages = {}
  72.  
  73.  
  74. checkTeleportTimers = {}
  75.  
  76. createChatCommands()
  77. createRanks()
  78. createSettings()
  79. loadPlayerData()
  80. createRankups()
  81.  
  82.  
  83. createScoreboard("playtime")
  84. createScoreboard("balance")
  85. getDroneData()
  86. createDroneActions()
  87. createRankInformationMessage()
  88.  
  89.  
  90. addTimeTimer = os.startTimer(60)
  91. checkJoinedPlayersTimer = os.startTimer(10)
  92. end
  93.  
  94.  
  95.  
  96. function createDroneActions() -- Creates all drone actions (a drone action is a list of functions that the drone will perform one after the other)
  97. createDroneAction("refuel",{"teleport","standby"})
  98. createDroneAction("teleportPlayer",{"importPlayer","teleport","exportEntity"})
  99. end
  100.  
  101.  
  102.  
  103. function getPeripherals() -- checks if all peripherals that are needed are connected to the computer and connects them
  104. chatBoxes = {}
  105. droneNames = {}
  106.  
  107.     for k,peripheralName in pairs(peripheral.getNames()) do
  108.    
  109.         if string.find(peripheralName,"playerDetector") then
  110.         playerDetector = peripheral.wrap(peripheralName)
  111.         end
  112.        
  113.         if peripheral.getType(peripheralName) == "modem" then
  114.         rednet.open(peripheralName)
  115.         end
  116.        
  117.         if string.find(peripheralName,"chatBox") then
  118.         table.insert(chatBoxes, {peripheral = peripheral.wrap(peripheralName), cooldownTime = 0})
  119.         end
  120.        
  121.         if string.find(peripheralName,"drone_interface") then
  122.         table.insert(droneNames, peripheralName)
  123.         end
  124.    
  125.     end
  126.    
  127.    
  128.     if not playerDetector then
  129.     error("No Player Detector found")
  130.     end
  131.    
  132.     if table.maxn(chatBoxes) < 1 then
  133.     error("No Chat Box found")
  134.     end
  135.  
  136. end
  137.  
  138.  
  139.  
  140. function createFiles() -- Creates all for the program necessary files/folders
  141. programFolderName = systemName
  142.  
  143.     if not fs.exists(programFolderName .. "/playerData") then
  144.     fs.makeDir(programFolderName .. "/playerData")
  145.     end
  146.  
  147. end
  148.  
  149.  
  150.  
  151. function createRanks() -- Creates all player ranks
  152. playerRanks = {}
  153. rankNames = {}
  154. standardRank = "Beginner"
  155.  
  156.  
  157. createRank("Supervisor",4,{}, "A supervisor is there to, you guessed it, supervise! They look after stuff like drones and Bugs. You can only become a Supervisor by being granted this Rank by an Admin or Owner.")
  158. createRank("Admin",5,{["canChangeOtherPlayersSettings"] = true}, "Same as a Supervisor, but can do more Stuff.")
  159. createRank("Owner",6,{["canChangeOtherPlayersSettings"] = true}, "They own the " .. systemName .. ".")
  160. createRank("Elder",3,{}, "To reach the Elder rank you need to play 3000 minutes on the server.\n As an Elder you can do nothing special at the moment. This will change in the future")
  161. createRank("Member",2,{}, "To reach the Member rank you need to play 500 minutes on the server.\n As a Member you can tp to other players.")
  162. createRank("Beginner",1,{}, "Everyone starts out as a Beginner. As a Beginner you only have basic permissions, to get more you need to rank up.")
  163. createRank("Banned",0,{["canChangeOtherPlayersSettings"] = false}, "You are Banned you cant do anything.")
  164. end
  165.  
  166.  
  167.  
  168. function createChatCommands() -- creates all chat commands (a chat command is a function that can be called by typing its name together with an @ in the chat)
  169. chatCommands = {}
  170. chatCommandNames = {}
  171.  
  172.  
  173. createChatCommand("help",1, "Lists all chat commands. As the first parameter either enter a number to change the help page or specify the name of a chat command to only get info about that command.")
  174. createChatCommand("about",1, "If you enter it without any parameters it gives you a list of what you can get information about.")
  175. createChatCommand("giveFeedback",1, "You can use this chat command to report bugs/problems or also to give ideas about new chat commands or things like settings.")
  176. createChatCommand("listSettings",1, "Lists all your settings.")
  177. createChatCommand("changeSetting",1, "The first parameter either needs to be the name of a player or the name of a setting. If you enter the name of a player, then the setting of that player will be changed either your setting will be changed. After that just enter the value you want the setting to be changed to.")
  178. createChatCommand("balance",1, "Shows your balance. If you enter a player as the first parameter then it shows the balance of that player.")
  179. createChatCommand("pay",1, "Pays the player that you enter as the first parameter the amount of credits that you specified as the second parameter.")
  180. createChatCommand("playtimeScoreboard",1, "Shows the playtime scoreboard. If the first parameter is blank, then it shows your position, if it is a number, then it shows the page with that number.")
  181. createChatCommand("balanceScoreboard",1, "Shows the balance scoreboard. If the first parameter is blank, then it shows your position, if it is a number, then it shows the page with that number.")
  182. createChatCommand("tp",1, "You can either enter a player as the first parameter or you can enter the x, y and z coordinates of your destination. If you enter \"Back\" as the first parameter you will be teleported to your last teleport position. The chunk you teleport to needs to be loaded.")
  183. createChatCommand("setRank",5, "Sets the rank of the player specified in the first parameter to the rank specified in the second parameter.")
  184. createChatCommand("ban",5, "Bans the player specified in the first parameter.")
  185. createChatCommand("unban",5, "Unbans the player specified in the first parameter.")
  186. end
  187.  
  188.  
  189.  
  190. function createSettings() -- creates all player settings
  191. settings = {}
  192. standardSettings = {}
  193.  
  194. createSetting("disableJoinMessage",false,0, "Disables the joining message.")
  195. createSetting("disablePatchMessage",false,0, "Disables the patch notes notifications.")
  196. createSetting("disableAllMessages",false,0, "Disables all system messages (not recommended).")
  197. createSetting("canChangeOtherPlayersSettings",false,5, "Allows you, to change other players settings.")
  198. end
  199.  
  200.  
  201.  
  202. function createRankups() -- creates all rankup conditions (such as how long you need to play to get a new rank)
  203. createRankup("Member", "playtime", 500)
  204. createRankup("Elder", "playtime", 3000)
  205. end
  206.  
  207.  
  208.  
  209. function loadPlayerData() -- loads the data of all registered players
  210. playerNames = fs.list(programFolderName .. "/playerData")
  211.     for k,playerName in pairs(playerNames) do
  212.     getPlayerData(playerName)
  213.     updateSettings(playerName)
  214.     end
  215. end
  216.  
  217.  
  218.  
  219. function updateSettings(playerName) -- checks if the settings of any player are outdated and changes them if necessary
  220.  
  221.     for settingName, settingValue in pairs(standardSettings) do
  222.         if not playerData[playerName]["settings"][settingName] then
  223.         playerData[playerName]["settings"][settingName] = settingValue
  224.         end
  225.     end
  226.    
  227.     for settingName, settingValue in pairs(playerData[playerName]["settings"]) do
  228.         if not settings[settingName] then
  229.         playerData[playerName]["settings"][settingName] = nil
  230.         end
  231.     end
  232.  
  233. savePlayerData(playerName)
  234. end
  235.  
  236.  
  237.  
  238. function createRankInformationMessage() -- creates the message about ranks that will be sent with the aboutFunctions.ranks function
  239. rankInformationMessage = {}
  240.  
  241.     for k,rankName in ipairs(rankNames) do
  242.     local rankTable = playerRanks[rankName]
  243.     table.insert(rankInformationMessage, {text = "\n" .. rankName, color = "green", hoverEvent = hoverMessage(rankTable["info"])})
  244.     table.insert(rankInformationMessage, {text = " - Permission level: ", hoverEvent = hoverMessage(rankTable["info"])})
  245.     table.insert(rankInformationMessage, {text = rankTable["permissionLevel"], color = "green", hoverEvent = hoverMessage(rankTable["info"])})
  246.     end
  247. end
  248. -------------------------------------
  249.  
  250.  
  251.  
  252.  
  253.  
  254. -- main functions -------------------
  255.  
  256. function main() -- the main function that runs the whole time and listens to events
  257.  
  258.     while true do
  259.     os.startTimer(0.25)
  260.     info1,info2,info3,info4 = os.pullEvent()
  261.     performDroneActions()
  262.        
  263.         if info1 == "chat" and not isMessageDouble() then
  264.             if not playerData[executingPlayer] then -- checks if player is registered
  265.             getPlayerData(info2)
  266.             end
  267.            
  268.         returnMessage,params = getChatCommand(info2,info3)
  269.             if returnMessage then -- checks if the message was a chat command
  270.             executingPlayer = info2
  271.                
  272.                
  273.                 if type(returnMessage) == "function" then -- checks if the chat command is valid
  274.                 local chatErrorMessage = returnMessage(params)
  275.                     if chatErrorMessage then
  276.                     sendMessage(chatErrorMessage,executingPlayer,"red")
  277.                     end
  278.                 else
  279.                 sendMessage(returnMessage,executingPlayer,"red") -- sends an error message
  280.                 end
  281.             end
  282.         end
  283.        
  284.        
  285.        
  286.         if info1 == "timer" then
  287.        
  288.             if info2 == addTimeTimer then
  289.             addTime()
  290.             checkRankups()
  291.             giveMoney()
  292.             end
  293.            
  294.            
  295.             if info2 == checkJoinedPlayersTimer then -- checks if a player joined the server
  296.             sendJoinMessages()
  297.             sendPatchNotes()
  298.             checkJoinedPlayersTimer = os.startTimer(10)
  299.             end
  300.        
  301.         end
  302.        
  303.     end
  304.    
  305. end
  306.  
  307. ------------------------------------
  308.  
  309.  
  310. -- Drone functions ------------------------------
  311.  
  312. function getDroneData(droneName) -- loads all drone data from the files
  313.  
  314.     if not droneName then
  315.     droneData = readFolder(programFolderName .. "/droneData")
  316.  
  317.         for k,droneName in pairs(droneNames) do
  318.             if not droneData[droneName] then
  319.             registerDrone(droneName)
  320.             else
  321.             droneData[droneName]["peripheral"] = peripheral.wrap(droneName)
  322.             end
  323.         end
  324.     else
  325.    
  326.     droneData[droneName] = readFolder(programFolderName .. "/droneData/" .. droneName)
  327.         if not droneData[droneName] then
  328.         registerDrone(droneName)
  329.         else
  330.         droneData[droneName]["peripheral"] = peripheral.wrap(droneName)
  331.         end
  332.     end
  333.  
  334. end
  335.  
  336.  
  337.  
  338. function registerDrone(droneName) -- registers a new drone (creates all the files and stuff)
  339. local dronePeripheral = peripheral.wrap(droneName)
  340.     if not dronePeripheral then
  341.     error("Not a valid drone interface")
  342.     end
  343.    
  344. droneData[droneName] ={["hasWork"] = false, ["peripheral"] = dronePeripheral}
  345. setDroneAction(droneName,"refuel",{refuelCoords})
  346. saveDroneData(droneName)
  347. end
  348.  
  349.  
  350.  
  351. function saveDroneData(droneName) -- saves the drone data in a file
  352.  
  353.     if droneName == "all" or (not droneData) then
  354.     saveTable(programFolderName .. "/droneData",droneData)
  355.     return
  356.     end
  357.  
  358.     if not droneData[droneName] then
  359.     registerDrone(droneName)
  360.     return
  361.     end
  362.    
  363. saveTable(programFolderName .. "/droneData/" .. droneName, droneData[droneName])
  364. end
  365.  
  366.  
  367.  
  368. function setDroneAction(droneName,action,params,controllingPlayer) -- sets the action of a drone
  369.     if not droneData[droneName] then
  370.     error("This drone does not exist.")
  371.     end
  372.    
  373.     if controllingPlayer then
  374.         if playerData[controllingPlayer]["lostDrone"] and action ~= "refuel" then
  375.         sendMessage("Because you have lost a drone, you currently cant use drones. Please try again later.", controllingPlayer, "red")
  376.         return false
  377.         end
  378.     end
  379.  
  380. droneData[droneName]["hasWork"] = true
  381. droneData[droneName]["actionName"] = action
  382. droneData[droneName]["startedFunctions"] = 0
  383. droneData[droneName]["controllingPlayer"] = controllingPlayer
  384. droneData[droneName]["params"] = params or {}
  385. droneData[droneName]["startTime"] = os.epoch("local")
  386. return true
  387. end
  388.  
  389.  
  390.  
  391. function createDroneAction(name, functions)
  392.     if type(name) ~= "string" then
  393.     error("name needs to be a string got " .. type(name))
  394.     end
  395.    
  396.     if type(functions) ~= "table" then
  397.     error("functions needs to be a table got " .. type(name))
  398.     end
  399.  
  400.  
  401. droneActions = droneActions or {}
  402.  
  403. local actionFunctions = {}
  404.     for k,v in pairs(functions) do
  405.     table.insert(actionFunctions,_ENV["droneFunctions"][v])
  406.     end
  407.  
  408. droneActions[name] = actionFunctions
  409. end
  410.  
  411.  
  412.  
  413. function disconnectDrone(droneName) -- disconnects the drone (this drone will not be used anymore till its reconnected)
  414.     if not droneData[droneName] then
  415.     error("A drone named \"" .. droneName .. "\" does not exist." )
  416.     end
  417.  
  418. local controller = droneData[droneName]["controllingPlayer"]
  419.  
  420. local file = fs.open(programFolderName .. "/disconnectedDrones", "a")
  421.     if controller then
  422.     file.write(os.date("local") .. ": The player \"" .. controller .. "\" has disconnected the drone named \"" .. droneName ..  "\"")
  423.     sendMessage("Your reputation decreased by 50, because you havent recovered the drone in time. To recover some of your lost reputation you can recover the drone at a later time.", controller, "red")
  424.     playerData[controller]["lostDrone"] = nil
  425.     giveReputation(controller, -50)
  426.     else
  427.     file.writeLine(os.date() .. ":  The drone named \"" .. droneName ..  "\" has been disconnected.")
  428.     end
  429.        
  430. file.flush()
  431. file.close()
  432.  
  433. droneData[droneName] = {["isDisconnected"] = true, ["hasWork"] = false, ["peripheral"] = droneData[droneName]["peripheral"]}
  434. saveDroneData(droneName)
  435. end
  436.  
  437.  
  438.  
  439. function performDroneActions() -- performs the drone actions of all drones
  440.     for droneName,drone in pairs(droneData) do
  441.     checkDroneStatus(droneName)
  442.         if drone["hasWork"] then
  443.         performDroneAction(droneName)
  444.         end
  445.     end
  446. end
  447.  
  448.  
  449.  
  450. function performDroneAction(droneName) -- performs the drone action of the specified drone
  451. local dronePeriph = droneData[droneName]["peripheral"]
  452.  
  453.     if not dronePeriph.isConnectedToDrone() then -- checks if the drone is connected
  454.     return "error"
  455.     end
  456.  
  457.     if os.epoch("local") - droneData[droneName]["startTime"] > 120000 then -- Checks if the drone takes too long to perform its action
  458.     finishAction(droneName)
  459.     end
  460.  
  461.     if droneData[droneName]["startedFunctions"] == 0 then -- Starts the first function of the drone
  462.     droneData[droneName]["startedFunctions"] = droneData[droneName]["startedFunctions"] + 1
  463.     droneActions[droneData[droneName]["actionName"]][droneData[droneName]["startedFunctions"]](droneName, droneData[droneName]["params"][droneData[droneName]["startedFunctions"]])
  464.     end
  465.    
  466.     if (not pcall(dronePeriph.isActionDone)) and droneData[droneName]["actionName"] then -- restarts the drone function if it got cancelled because of something like a server restart
  467.     droneActions[droneData[droneName]["actionName"]][droneData[droneName]["startedFunctions"]](droneName, droneData[droneName]["params"][droneData[droneName]["startedFunctions"]])
  468.     end
  469.    
  470.    
  471.     if dronePeriph.isActionDone() then -- starts next function or completes the action
  472.         if droneData[droneName]["startedFunctions"] == table.maxn(droneActions[droneData[droneName]["actionName"]]) then
  473.         finishAction(droneName)
  474.         return
  475.         end
  476.     droneData[droneName]["startedFunctions"] = droneData[droneName]["startedFunctions"] + 1
  477.     droneActions[droneData[droneName]["actionName"]][droneData[droneName]["startedFunctions"]](droneName, droneData[droneName]["params"][droneData[droneName]["startedFunctions"]])
  478.     saveDroneData(droneName)
  479.     end
  480.  
  481. end
  482.  
  483.  
  484.  
  485. function finishAction(droneName, errorMessage) -- cancels/finishes the action of the drone
  486.  
  487.     if droneData[droneName]["controllingPlayer"] and droneData[droneName]["actionName"] ~= "refuel" then
  488.         if errorMessage then
  489.         sendMessage(errorMessage, droneData[droneName]["controllingPlayer"] ,"red")
  490.         elseif checkPlayerTpFailure(droneName) then
  491.         sendMessage("Teleportation failed, please only teleport to loaded chunks", droneData[droneName]["controllingPlayer"], "red")
  492.         else
  493.         sendMessage("The drone named \"" .. droneName .. "\" has finished its task.", droneData[droneName]["controllingPlayer"], "green")
  494.         end
  495.     end
  496.  
  497.     if droneData[droneName]["actionName"] == "refuel" then
  498.     droneData[droneName]["startedFunctions"] = nil
  499.     droneData[droneName]["hasWork"] = false
  500.     droneData[droneName]["params"] = nil
  501.     droneData[droneName]["actionName"] = nil
  502.     droneData[droneName]["controllingPlayer"] = nil
  503.     droneData[droneName]["actionName"] = nil
  504.     droneData[droneName]["startTime"] = nil
  505.     else
  506.     refuelDrone(droneName, droneData[droneName]["controllingPlayer"])
  507.     end
  508.    
  509. saveDroneData(droneName)
  510. end
  511.  
  512.  
  513.  
  514. function checkPlayerTpFailure(droneName) -- checks if the player that was teleported has reached his destination
  515. local playerName = droneData[droneName]["controllingPlayer"]
  516.  
  517.     if droneData[droneName]["actionName"] ~= "teleportPlayer" or not table.contains(playerDetector.getOnlinePlayers(), playerName) then
  518.     return false
  519.     end
  520.  
  521. local x = droneData[droneName]["params"][droneData[droneName]["startedFunctions"]-1]["x"]
  522. local y = droneData[droneName]["params"][droneData[droneName]["startedFunctions"]-1]["y"]
  523. local z = droneData[droneName]["params"][droneData[droneName]["startedFunctions"]-1]["z"]
  524. local playerPos = playerDetector.getPlayerPos(playerName)
  525. local pX = playerPos["x"]
  526. local pY = playerPos["y"]
  527. local pZ = playerPos["z"]
  528.  
  529.     if not (pX > x-10 and pX < x+10 and pY > y-10 and pY < y+10 and pZ > z-10 and pZ < z+10) then
  530.     droneFunctions.exportEntity(droneName)
  531.     return true
  532.     end
  533. end
  534.  
  535.  
  536.  
  537. function checkDroneStatus(droneName) -- checks if the drone was disconnected/reconnected etc.
  538. checkDroneDisconnection(droneName)
  539. checkCancelledDroneDisconnection(droneName)
  540. checkDroneReconnection(droneName)
  541. end
  542.  
  543.  
  544.  
  545. function checkDroneDisconnection(droneName) -- checks if the drone was disconnected
  546.     if (not droneData[droneName]["peripheral"].isConnectedToDrone()) and (not droneData[droneName]["isDisconnected"]) then
  547.         if not droneData[droneName]["disconnectTime"] and droneData[droneName]["controllingPlayer"] then
  548.         sendMessage("The drone named \"" .. droneName .. "\" you were using has been disconnected, please recover the drone (replace it in the world) within 60 seconds, if you dont, and this happens too often, you will get banned.", droneData[droneName]["controllingPlayer"], "red")
  549.         playerData[droneData[droneName]["controllingPlayer"]]["lostDrone"] = true
  550.         savePlayerData(droneData[droneName]["controllingPlayer"])
  551.         end
  552.        
  553.         if not droneData[droneName]["disconnectTime"] then
  554.         droneData[droneName]["disconnectTime"] = os.epoch("local")
  555.         saveDroneData(droneName)
  556.         elseif os.epoch("local") - droneData[droneName]["disconnectTime"] > 60000 then
  557.         disconnectDrone(droneName)
  558.         end
  559.     end
  560. end
  561.  
  562.  
  563.  
  564. function checkCancelledDroneDisconnection(droneName) -- checks if the drone disconnection was cancelled
  565.     if droneData[droneName]["disconnectTime"] and droneData[droneName]["peripheral"].isConnectedToDrone() then
  566.     droneData[droneName]["disconnectTime"] = nil
  567.     refuelDrone(droneName, droneData[droneName]["peripheral"].getOwnerName())
  568.         if droneData[droneName]["controllingPlayer"] then
  569.         sendMessage("The drone named \"" .. droneName .. "\" has been reconnected.", droneData[droneName]["controllingPlayer"], "green")
  570.         playerData[droneData[droneName]["controllingPlayer"]]["lostDrone"] = nil
  571.         savePlayerData(droneData[droneName]["controllingPlayer"])
  572.         end
  573.     end
  574. end
  575.  
  576.  
  577.  
  578. function checkDroneReconnection(droneName) -- checks if the drone was reconnected
  579.     if droneData[droneName]["isDisconnected"] and droneData[droneName]["peripheral"].isConnectedToDrone() then
  580.     droneData[droneName]["isDisconnected"] = nil
  581.     droneData[droneName]["disconnectTime"] = nil
  582.     saveDroneData(droneName)
  583.     refuelDrone(droneName, droneData[droneName]["peripheral"].getOwnerName())
  584.     giveReputation(droneData[droneName]["peripheral"].getOwnerName(), 25)
  585.     sendMessage("You have gained 25 reputation for reconnecting the drone named \"" .. droneName .. "\".", droneData[droneName]["peripheral"].getOwnerName(), "green")
  586.     end
  587. end
  588.  
  589.  
  590.  
  591. function refuelDrone(droneName,player) -- refuels the drone
  592.     if not droneData[droneName] then
  593.     error("The drone named " .. droneName .. " does not exist.")
  594.     end
  595. setDroneAction(droneName,"refuel",{refuelCoords},player)
  596. end
  597.  
  598.  
  599.  
  600. function getFreeDrone() -- gets the first free drone (a drone that currently does not perform an action)
  601.  
  602.     for droneName,drone in pairs(droneData) do
  603.         if not drone["hasWork"] and not drone["isDisconnected"] then
  604.         return droneName
  605.         end
  606.     end
  607.  
  608. end
  609.  
  610.  
  611.  
  612. function getConnectedDroneCount() -- gets the count of connected drones
  613. local count = 0
  614.     for k,v in pairs(droneData) do
  615.         if not v["isDisconnected"] then
  616.         count = count + 1
  617.         end
  618.     end
  619. return count
  620. end
  621.  
  622.  
  623.  
  624. function droneFunctions.teleport(droneName,params) -- teleports the drone to the specified coordinates
  625.  
  626.     if not params then
  627.     finishAction(droneName, "The teleportation was stopped because of an unexpected error.")
  628.     return
  629.     end
  630.    
  631. local dronePeriph = droneData[droneName]["peripheral"]
  632. local x = params["x"]
  633. local y = params["y"]
  634. local z = params["z"]
  635.  
  636. dronePeriph.clearArea()
  637. dronePeriph.addArea(x,y,z)
  638.  
  639. dronePeriph.abortAction()
  640. dronePeriph.setAction("goto")
  641. end
  642.  
  643.  
  644.  
  645. function droneFunctions.standby(droneName) -- sets the drone to be on standby
  646. droneData[droneName]["peripheral"].abortAction()
  647. droneData[droneName]["peripheral"].setAction("standby")
  648. end
  649.  
  650.  
  651.  
  652. function droneFunctions.importPlayer(droneName,params) -- picks up the player that is controlling the drone
  653.  
  654.     if not params then
  655.     finishAction(droneName, "The player import was stopped because of an unexpected error.")
  656.     return
  657.     end
  658.  
  659. local x1 = params["x"] - 3
  660. local y1 = params["y"] - 3
  661. local z1 = params["z"] - 3
  662. local x2 = params["x"] + 3
  663. local y2 = params["y"] + 3
  664. local z2 = params["z"] + 3
  665.  
  666. local dronePeriph = droneData[droneName]["peripheral"]
  667.  
  668.  
  669. dronePeriph.clearArea()
  670. dronePeriph.addArea(x1,y1,z1,x2,y2,z2,"Filled")
  671.  
  672. dronePeriph.clearWhitelistText()
  673. dronePeriph.clearBlacklistText()
  674. dronePeriph.addWhitelistText("player")
  675.  
  676. dronePeriph.abortAction()
  677. dronePeriph.setAction("entity_import")
  678. end
  679.  
  680.  
  681.  
  682. function droneFunctions.exportEntity(droneName) -- exports the entity that the drone is currently carrying
  683. local dronePeriph = droneData[droneName]["peripheral"]
  684. dronePeriph.clearWhitelistText()
  685. dronePeriph.clearBlacklistText()
  686. dronePeriph.clearArea()
  687. dronePeriph.addArea(dronePeriph.getDronePosition())
  688. dronePeriph.abortAction()
  689. dronePeriph.setAction("entity_export")
  690. end
  691. -------------------------------------------------
  692.  
  693.  
  694.  
  695.  
  696. -- Settings and data functions -------------------
  697.  
  698. function getPlayerSetting(setting,player) -- get the value of the specified setting of the specified player
  699.     if not playerData[player] then
  700.     error(player .. " is not a registered player.")
  701.     end
  702.    
  703.     if not settings[setting] then
  704.     error(setting .. " is not a setting")
  705.     end
  706.  
  707. return playerData[player]["settings"][setting] or settings[setting]["standardValue"]
  708. end
  709.  
  710.  
  711.  
  712. function createSetting(name,standardValue,requiredPermLevl,info) -- creates a player setting
  713. settings[name] = {}
  714. settings[name]["standardValue"] = standardValue
  715. settings[name]["requiredPermLevl"] = requiredPermLevl
  716. settings[name]["type"] = type(standardValue)
  717. settings[name]["info"] = info
  718.  
  719. settingNames = settingNames or {}
  720. table.insert(settingNames,name)
  721.  
  722. standardSettings[name] = standardValue
  723. end
  724.  
  725.  
  726.  
  727. function changeSetting(player,setting,value) -- changes the setting of a player
  728.  
  729.     if not table.contains(playerNames,player) then
  730.     error("not a viable player")
  731.     end
  732.    
  733.    
  734.     if not settings[setting] then
  735.     error("not a viable setting")
  736.     end
  737.  
  738.  
  739.     if type(value) ~= settings[setting]["type"] then
  740.     error("bad argument #3 (value supposed to have the type " .. settings[setting]["type"] .. " but has the type" .. type(value) .. ")")
  741.     end
  742.    
  743. playerData[player]["settings"][setting] = value
  744. saveTable(programFolderName .. "/playerData/" .. player .. "/settings", playerData[player]["settings"])
  745. end
  746.  
  747.  
  748.  
  749. function addTime() -- adds playtime to all players
  750.     for k,player in pairs(playerDetector.getOnlinePlayers()) do
  751.         if not playerData[player] then -- registers the player if they are new
  752.         getPlayerData(player)
  753.         end
  754.     playerData[player]["stats"]["playtime"] = playerData[player]["stats"]["playtime"] + 1
  755.         if playerData[player]["stats"]["playtime"] % 60 == 0 then
  756.         giveMoney(player, 150)
  757.         end
  758.     savePlayerData(player, "stats")
  759.     updateScoreboard("playtime", player)
  760.     end
  761. addTimeTimer = os.startTimer(60)
  762. end
  763.  
  764.  
  765.  
  766. function updateScoreboard(data, player) -- updates position of the specified player in the specified scoreboard
  767.     if not scoreboards[data] then
  768.     error("This scoreboard does not exist")
  769.     end
  770.  
  771. local score = playerData[player]["stats"][data]
  772. local position = getScoreboardPosition(data, player)
  773.  
  774.     if not position then -- adds the player to the end of the scoreboard if they dont have a position yet
  775.     table.insert(scoreboards[data], {["playerName"] = player, ["score"] = score})
  776.     end
  777.  
  778.  
  779. scoreboards[data][position]["score"] = score
  780.  
  781.  
  782.     if position ~= 1 then
  783.         while score > scoreboards[data][position-1]["score"] do -- ckecks if the score of the player is higher than the players in the spots over them
  784.         table.remove(scoreboards[data], position)
  785.         position = position - 1
  786.         table.insert(scoreboards[data], position, {["playerName"] = player, ["score"] = score})
  787.             if position == 1 then
  788.             return
  789.             end
  790.         end
  791.     end
  792.    
  793.     if scoreboards[data][position+1] then
  794.         while score < scoreboards[data][position+1]["score"] do -- ckecks if the score of the player is lower than the players in the spots under them
  795.         table.remove(scoreboards[data], position)
  796.         position = position + 1
  797.         table.insert(scoreboards[data], position, {["playerName"] = player, ["score"] = score})
  798.             if not scoreboards[data][position+1] then
  799.             return
  800.             end
  801.         end
  802.     end
  803.    
  804. end
  805.  
  806.  
  807.  
  808. function getScoreboardPosition(data, player) -- gets the position of a specified player in a specified scoreboard
  809.     if not scoreboards[data] then
  810.     error("This scoreboard does not exist")
  811.     end
  812.  
  813.     for k,v in pairs(scoreboards[data]) do
  814.         if v["playerName"] == player then
  815.         return k
  816.         end
  817.     end
  818. end
  819.  
  820.  
  821.  
  822. function createScoreboard(data) -- creates a scoreboard (the variable data needs to be a index of the playerData[playerName]["stats"] table)
  823. scoreboards = scoreboards or {}
  824. local returnTable = {}
  825. local scores = {}
  826. local temporaryTable = {}
  827.  
  828.     for k,v in pairs(playerData) do
  829.     temporaryTable[v["stats"][data]] = temporaryTable[v["stats"][data]] or {}
  830.     table.insert(temporaryTable[v["stats"][data]], k)
  831.         if not table.contains(scores, v["stats"][data]) then
  832.         table.insert(scores,v["stats"][data])
  833.         end
  834.     end
  835.  
  836.  
  837. scores = sortScores(scores)
  838.  
  839.    
  840. local maxn = table.maxn(scores)
  841.     for k,v in pairs(scores) do
  842.         for k2,v2 in pairs(temporaryTable[v]) do
  843.         table.insert(returnTable, table.maxn(returnTable)+1, {playerName = v2, score = v})
  844.         end
  845.     end
  846.  
  847. scoreboards[data] = returnTable
  848. end
  849.  
  850.  
  851.  
  852. function sortScores(scores) -- sorts the scores of a scoreboard in the right order
  853. local returnTable = {[1] = scores[table.maxn(scores)]}
  854. scores[table.maxn(scores)] = nil
  855.     for k,v in pairs(scores) do
  856.     local worked = false
  857.         for k2,v2 in pairs(returnTable) do
  858.             if v > v2 then
  859.             table.insert(returnTable,k2 , v)
  860.             worked = true
  861.             break
  862.             end
  863.         end
  864.        
  865.         if not worked then
  866.         table.insert(returnTable, v)
  867.         end
  868.     end
  869.    
  870. return returnTable
  871. end
  872.  
  873. ----------------------------------------
  874.  
  875.  
  876.  
  877.  
  878. -- player functions ---------------
  879.  
  880. function getJoinedPlayer() -- checks if a player joined the server
  881. onlinePlayers = onlinePlayers or {}
  882. local returnTable = {}
  883.  
  884.     for k, playerName in pairs(playerDetector.getOnlinePlayers()) do
  885.         if not table.contains(onlinePlayers, playerName) then
  886.         table.insert(onlinePlayers, playerName)
  887.             if playerData[playerName] then
  888.             table.insert(returnTable, playerName)
  889.             end
  890.         end
  891.     end
  892.  
  893. return returnTable
  894. end
  895.  
  896.  
  897.  
  898. function isPlayerOnline(player) -- checks if the player is online
  899. return table.contains(playerDetector.getOnlinePlayers(),player)
  900. end
  901.  
  902.  
  903.  
  904. function giveReputation(player, amount) -- gives reputation to the player
  905.  
  906.     if not playerData[player]["stats"]["reputation"] then
  907.     playerData[player]["stats"]["reputation"] = amount
  908.     else
  909.     playerData[player]["stats"]["reputation"] = playerData[player]["stats"]["reputation"] + amount
  910.     end
  911.    
  912.     if playerData[player]["stats"]["reputation"] <= -100 and playerData[player]["rank"] ~= "Banned" then -- checks if the player should be banned
  913.     banPlayer(player)
  914.     elseif playerData[player]["stats"]["reputation"] > -100 and playerData[player]["rank"] == "Banned" then -- chekcs if the player should be unbanned
  915.     unbanPlayer(player)
  916.     end
  917.    
  918. savePlayerData(player)
  919. end
  920.  
  921.  
  922.  
  923. function unbanPlayer(player, unbanningPlayer) -- unbanns the specified player
  924.  
  925.     if unbanningPlayer then
  926.     sendMessage("You have been unbanned from the " .. systemName .. " by " .. unbanningPlayer .. ".", player, "green")
  927.     sendMessage("You have succesfully unbanned the player " .. player .. ".", unbanningPlayer, "green")
  928.     setPlayerRank(player, getRankByPlaytime(player))
  929.     else
  930.     sendMessage("You have been unbanned from the " .. systemName .. ".", player, "green")
  931.     setPlayerRank(player, getRankByPlaytime(player))
  932.     end
  933.  
  934. savePlayerData(player)
  935. end
  936.  
  937.  
  938.  
  939. function banPlayer(player, banningPlayer) -- banns the specified player
  940.  
  941.     if banningPlayer then
  942.         if getPermissionLevel(banningPlayer) > getPermissionLevel(player) then
  943.         sendMessage("You have been banned from the " .. systemName .. " by " .. banningPlayer .. ". If you think this is unfair, please message someon of the rank of supervisor or higher.", player, "red")
  944.         sendMessage("You have succesfully banned the player " .. player .. ".", banningPlayer, "green")
  945.         setPlayerRank(player, "Banned")
  946.         else
  947.         sendMessage("Your permission level isnt high enaugh to ban this player.", banningPlayer, "red")
  948.         end
  949.     else
  950.     sendMessage("You have been banned from the " .. systemName .. ". If you think this is unfair, please message someon of the rank of supervisor or higher.", player, "red")
  951.     setPlayerRank(player, "Banned")
  952.     end
  953.  
  954. savePlayerData(player)
  955. end
  956.  
  957.  
  958.  
  959. function getRankByPlaytime(playerName) -- checks what rank the player would have based on their playtime (used for unbannig)
  960. local curHighestRank = "Beginner"
  961.     for rankupName,rankup in pairs(rankups) do
  962.         if playerData[playerName]["stats"][rankup["statName"]] >= rankup["condition"] and playerRanks[curHighestRank]["permissionLevel"] < playerRanks[rankupName]["permissionLevel"] then
  963.         curHighestRank = rankupName
  964.         end
  965.     end
  966. return curHighestRank
  967. end
  968.  
  969.  
  970.  
  971. function giveMoney(player,amount) -- gives money to the specified player
  972.    
  973.     if not table.contains(playerNames,player) then
  974.     return
  975.     end
  976.    
  977.     if playerData[player]["stats"]["balance"] then
  978.     playerData[player]["stats"]["balance"] = playerData[player]["stats"]["balance"] + amount
  979.     else
  980.     playerData[player]["stats"]["balance"] = amount
  981.     end
  982.  
  983. updateScoreboard("balance", player)
  984. sendMessage({"You have received ", {text = amount .. "c", color = "green"}, ".\nBalance: ", {text = playerData[player]["stats"]["balance"], color = "green"}},player)
  985. end
  986.  
  987.  
  988.  
  989. function getPlayerData(player) -- gets the data of a player
  990. playerData[player] = {}
  991.  
  992.     if fs.exists(programFolderName .. "/playerData/" .. player) then
  993.     playerData[player] = readFolder(programFolderName .. "/playerData/" .. player)
  994.     else
  995.     registerNewPlayer(player)
  996.     end
  997.  
  998. end
  999.  
  1000.  
  1001.  
  1002. function registerNewPlayer(player) -- registers a new player
  1003.  
  1004. playerData[player]["rank"] = standardRank
  1005. playerData[player]["settings"] = standardSettings
  1006. playerData[player]["stats"] = {
  1007. ["playtime"] = 0,
  1008. ["balance"] = 250,
  1009. ["reputation"] = 0
  1010. }
  1011.  
  1012. table.insert(playerNames,player)
  1013.  
  1014. saveTable(programFolderName .. "/playerData",playerData)
  1015.  
  1016.  
  1017. updateScoreboard("playtime", player)
  1018. updateScoreboard("balance", player)
  1019.  
  1020.  
  1021. sendMessage("Congratulations, you have been registered to the " .. systemName .. ", you can use it for things like teleporting, paying other players or getting stat ranklists. Type \"@help\" for more info.", player, "green")
  1022. end
  1023.  
  1024.  
  1025.  
  1026. function savePlayerData(player,saveWhat) -- saves the data of a player (if player is "all" then it saves the data of all players, if saveWhat is nil it saves the whole playerData)
  1027.    
  1028.     if player == "all" then
  1029.         for k,v in pairs(playerData) do
  1030.         savePlayerData(k, saveWhat)
  1031.         end
  1032.    
  1033.     else
  1034.         if saveWhat then
  1035.             if not playerData[player][saveWhat] then
  1036.             error(saveWhat .. "is not a existing playerData")
  1037.             end
  1038.         saveTable(programFolderName .. "/playerData/" .. player .. "/" .. saveWhat, playerData[player][saveWhat])
  1039.         else
  1040.         saveTable(programFolderName .. "/playerData/" .. player, playerData[player])
  1041.         end
  1042.     end
  1043.  
  1044. end
  1045.  
  1046.  
  1047.  
  1048. function setPlayerRank(player,rank) -- sets the rank of the specified player
  1049.  
  1050.     if not table.contains(playerNames,player) then
  1051.     error("bad argument #1 (" .. player .. " is not a viable player)")
  1052.     elseif not table.contains(rankNames,rank) then
  1053.     error("bad argument #1 (" .. rank .. " is not a viable rank)")
  1054.     end
  1055.    
  1056. playerData[player]["rank"] = rank
  1057.  
  1058.     for k,v in pairs(playerRanks[rank]["settings"]) do
  1059.     playerData[player]["settings"][k] = v
  1060.     end
  1061.  
  1062. savePlayerData(player)
  1063. end
  1064.  
  1065.  
  1066.  
  1067. function createRank(name,permissionLevel,rankSettings,info) -- creates a player rank (the rank settings are all the settings that will be changed when a player reaches that rank. its a table in the format {[settingName] = settingValue})
  1068.  
  1069.     if type(name) ~= "string" then
  1070.     error("bad argument #1 (name is supposed to be a string)")
  1071.     elseif type(permissionLevel) ~= "number" then
  1072.     error("bad argument #2 (permissionLevel is supposed to be a number)")
  1073.     end
  1074.  
  1075. playerRanks[name] = {
  1076. ["allowedChatCommands"] = allowedChatCommands,
  1077. ["permissionLevel"] = permissionLevel,
  1078. ["settings"] = rankSettings or {},
  1079. ["info"] = info
  1080. }
  1081.  
  1082.  
  1083. table.insert(rankNames,name)
  1084. end
  1085.  
  1086.  
  1087.  
  1088. function getPermissionLevel(player) -- gets the permission level of a player based on their rank
  1089. return playerRanks[playerData[player]["rank"]]["permissionLevel"] or 0
  1090. end
  1091.  
  1092.  
  1093.  
  1094. function isPermLevelHigher(playerOne,playerTwo) -- checks if the permission level of playerOne is higher than that of player two
  1095. return getPermissionLevel(playerOne) > getPermissionLevel(playerTwo)
  1096. end
  1097.  
  1098.  
  1099.  
  1100. function createRankup(rank, statName, condition) -- creates a rankup, players will automatically rank up to that rank if the player has the specified value of the data specified in statName
  1101. rankups = rankups or {}
  1102.  
  1103. rankups[rank] =
  1104. {["statName"] = statName,
  1105. ["condition"] = condition
  1106. }
  1107. end
  1108.  
  1109.  
  1110.  
  1111. function checkRankups() -- checks if any of the online players are supposed to rank up
  1112.  
  1113.     for k,player in pairs(playerDetector.getOnlinePlayers()) do
  1114.     checkRankup(player)
  1115.     end
  1116.  
  1117. end
  1118.  
  1119.  
  1120.  
  1121. function checkRankup(player) -- checks if the specified player is supposed to rank up (if so they will get ranked up)
  1122.  
  1123.     for rankupName,rankup in pairs(rankups) do
  1124.         if playerData[player]["stats"][rankup["statName"]] == rankup["condition"] and playerRanks[rankupName]["permissionLevel"] > playerRanks[playerData[player]["rank"]]["permissionLevel"] then
  1125.         setPlayerRank(player, rankupName)
  1126.         sendMessage("Congratulations, your rank is now " .. rankupName .. ".")
  1127.         return
  1128.         end
  1129.     end
  1130.  
  1131. end
  1132.  
  1133. -------------------------
  1134.  
  1135.  
  1136.  
  1137.  
  1138.  
  1139. -- chat functions -------------
  1140.  
  1141. function sendJoinMessages() -- sends a welcome message to all newly joined players
  1142.     for k,playerName in pairs(getJoinedPlayer()) do
  1143.         if playerData[playerName] then
  1144.             if not getPlayerSetting("disableJoinMessage", playerName) then
  1145.             sendMessage({{text = "\nWelcome back to the server. For more info on the " .. systemName .. " enter @help.", hoverEvent = hoverMessage("shift + click to disable this message."), insertion = "$@changeSetting disableJoinMessage true"}}, playerName, "green")
  1146.             end
  1147.         end
  1148.     end
  1149. end
  1150.  
  1151.  
  1152.  
  1153. function sendPatchNotes() -- sends the newest patchnotes if the player joined the current version for the first time
  1154.  
  1155.     for k,playerName in pairs(playerDetector.getOnlinePlayers()) do
  1156.         if playerData[playerName]["latestVersion"] ~= curVersion then
  1157.         playerData[playerName]["latestVersion"] = curVersion
  1158.         savePlayerData(playerName)
  1159.             if not getPlayerSetting("disablePatchMessage", playerName) then
  1160.             sendMessage({{text = "\nPatch notes " .. curVersion .. ":\n", hoverEvent = hoverMessage("shift + click to disable this message."), insertion = "$@changeSetting disablePatchMessage true", color = "green"},{text = patchNotes, hoverEvent = hoverMessage("shift + click to disable this message."), insertion = "$@changeSetting disablePatchMessage true" }}, playerName)
  1161.             end
  1162.         end
  1163.     end
  1164. end
  1165.  
  1166.  
  1167.  
  1168. function isMessageDouble() -- checks if the chat event is double (if multiple chatboxes are connected to the same computer there will be multiple events for each message)
  1169.  
  1170.     if os.epoch("local") - (lastMessageTime or 0) < 100 and lastMessagePlayer == info2 then
  1171.     return true
  1172.     end
  1173.    
  1174. lastMessageTime = os.epoch("local")
  1175. lastMessagePlayer = info2
  1176.  
  1177. end
  1178.  
  1179.  
  1180.  
  1181. function createChatCommand(name,requiredPermLevl,info) -- creats a chat command, if someon types @[name] in the chat the function named chatFunctions.[name] will be executed
  1182.    
  1183.     if type(name) ~= "string" then
  1184.     error("bad argument #1 (name is supposed to be a string)")
  1185.     elseif type(requiredPermLevl) ~= "number" then
  1186.     error("bad argument #2 (requiredPermLevl is supposed to be a number)")
  1187.     elseif type(info) ~= "string" then
  1188.     error("bad argument #3 (info is supposed to be a string)")
  1189.     end
  1190.    
  1191. chatCommands[name] = {
  1192. ["requiredPermLevl"] = requiredPermLevl,
  1193. ["function"] = _ENV["chatFunctions"][name],
  1194. ["info"] = info
  1195. }
  1196.  
  1197. table.insert(chatCommandNames,name)
  1198. end
  1199.  
  1200.  
  1201.  
  1202. function getChatCommand(player,message) -- checks if the chat message was a chat command and also returns the parameters written into the chat if the message was a chat command
  1203.     if string.sub(message,1,1) == "@" then
  1204.     chatCommand = string.sub(message,2,(string.find(message," ") or 0) -1)
  1205.    
  1206.         if chatCommands[chatCommand] then
  1207.             if getPermissionLevel(player) >= chatCommands[chatCommand]["requiredPermLevl"] then
  1208.            
  1209.             messageRest = string.sub(message,string.len(chatCommand)+3)
  1210.             local params = {}
  1211.            
  1212.             i = 1
  1213.                 while string.len(messageRest) ~= 0 do
  1214.                 params[i] = string.sub(messageRest,1,(string.find(messageRest," ") or 0) -1)
  1215.                 messageRest = string.sub(messageRest,string.len(params[i])+2)
  1216.                 i = i+1
  1217.                 end
  1218.                
  1219.             return chatCommands[chatCommand]["function"], params
  1220.            
  1221.             else
  1222.             return "You do not have permission to use this command."
  1223.             end
  1224.         else
  1225.         return "This command does not exist."
  1226.         end
  1227.    
  1228.     end
  1229. end
  1230.  
  1231.  
  1232.  
  1233. function sendMessage(message,player,color) -- sends a message to the specified player, the message can be a normal string or a table. For more info go to https://docs.advanced-peripherals.de/latest/peripherals/chat_box/#sendformattedmessage
  1234.  
  1235.     if not isPlayerOnline(player) then
  1236.     return false
  1237.     end
  1238.  
  1239.     if getPlayerSetting("disableAllMessages", player) then
  1240.     return false
  1241.     end
  1242.    
  1243. table.insert(sendTheseMessages, {message = message, player = player, color = color or "white"})
  1244. os.queueEvent("sendMessage")
  1245. end
  1246.  
  1247.  
  1248.  
  1249. function hoverMessage(message) -- returns the table used for a hoverEvent in the sendMessage function for more info also check https://docs.advanced-peripherals.de/latest/peripherals/chat_box/#sendformattedmessage
  1250. return {action = "show_text",value = message}
  1251. end
  1252.  
  1253.  
  1254.  
  1255. function showScoreboard(data, player, page, extraText) -- shows the specified scoreboard to the specified player (in form of a chat message)
  1256.     if not scoreboards[data] then
  1257.     error("This scoreboard does not exist")
  1258.     return
  1259.     end
  1260.    
  1261. local page = page or math.ceil(getScoreboardPosition(data, player)/10) -- sets the page to the page the executing player is on if the page isnt specified
  1262.  
  1263.     if not scoreboards[data][page*10-9] then
  1264.     sendMessage("This page does not exist", player, "red")
  1265.     return
  1266.     end
  1267.    
  1268.    
  1269. local message = {"\n"}
  1270.     for i = 1,10 do
  1271.     position = (page-1)*10+i
  1272.         if not scoreboards[data][position] then
  1273.         break
  1274.         end
  1275.  
  1276.     table.insert(message, {text = "#" .. position .. " ", color = "green"})
  1277.    
  1278.     local color = "white"
  1279.         if scoreboards[data][position]["playerName"] == player then
  1280.         color = "green"
  1281.         elseif position == 1 then
  1282.         color = "#ffe400"
  1283.         elseif position == 2 then
  1284.         color = "#c0cbe4"
  1285.         elseif position == 3 then
  1286.         color = "#c46403"
  1287.         end
  1288.     table.insert(message, {text = scoreboards[data][position]["playerName"] .. ": " .. scoreboards[data][position]["score"] .. (extraText or "") .. "\n", color = color})
  1289.     end
  1290.  
  1291. sendMessage(message, player)
  1292. end
  1293.  
  1294.  
  1295.  
  1296. function combineFormattedMessages(messages) -- a function used in the help chat command to format the message because im to lazy to do it properly
  1297. local returnTable = {}
  1298.  
  1299.     for k,message in pairs(messages) do
  1300.         for k2, v in pairs(message) do
  1301.         table.insert(returnTable, v)
  1302.         end
  1303.     end
  1304.  
  1305. return returnTable
  1306. end
  1307.  
  1308.  
  1309.  
  1310. function getOwnersText() -- returns a text about the owner*s of the system (used for the about sytem command)
  1311. local owners = ""
  1312. local ownerCount = 0
  1313.     for name,data in pairs(playerData) do
  1314.         if data["rank"] == "Owner" then
  1315.         ownerCount = ownerCount + 1
  1316.             if ownerCount == 1 then
  1317.             owners = name
  1318.             else
  1319.             owners = owners .. ", " .. name
  1320.             end
  1321.         end
  1322.     end
  1323.  
  1324. local ownersText = {}
  1325.  
  1326.     if ownerCount == 1 then
  1327.     table.insert(ownersText, {text = "Owner: ", color = "green"})
  1328.     else
  1329.     table.insert(ownersText, {text = "Owners: ", color = "green"})
  1330.     end
  1331.  
  1332.     if ownerCount == 0 then
  1333.     table.insert(ownersText, "None")
  1334.     else
  1335.     table.insert(ownersText, owners)
  1336.     end
  1337.    
  1338. return ownersText[1], ownersText[2]
  1339. end
  1340.  
  1341.  
  1342.  
  1343. function aboutFunctions.system() -- gives the executing player information about the system (in form of a chat message)
  1344. local ownerOrOwners, ownerNames = getOwnersText()
  1345.  
  1346.  
  1347. sendMessage({
  1348. {text = "\nFirst startup date: ", color = "green"},
  1349. firstStartupDate .. "\n",
  1350. ownerOrOwners,
  1351. ownerNames,
  1352. {text = "\nRegistered player count: ", color = "green"},
  1353. table.maxn(playerNames),
  1354. {text = "\nConnected drone count: ", color = "green"},
  1355. getConnectedDroneCount(),
  1356. {text = "\nMain program pastebin link: ", color = "green", clickEvent = {action = "open_url", value = "https://pastebin.com/" .. mainProgramLink}, hoverEvent = hoverMessage("Click to open link.")},
  1357. {text = mainProgramLink, clickEvent = {action = "open_url", value = "https://pastebin.com/" .. mainProgramLink}, hoverEvent = hoverMessage("Click to open link.")},
  1358. {text = "\nMessage sender pastebin link: ", color = "green", clickEvent = {action = "open_url", value = "https://pastebin.com/" .. messageSenderLink}, hoverEvent = hoverMessage("Click to open link.")},
  1359. {text = messageSenderLink, clickEvent = {action = "open_url", value = "https://pastebin.com/" .. messageSenderLink}, hoverEvent = hoverMessage("Click to open link.")}
  1360. }, executingPlayer)
  1361. end
  1362.  
  1363.  
  1364.  
  1365. function aboutFunctions.ranks() -- Gives the executingPlayer player information about all ranks.
  1366. sendMessage(rankInformationMessage, executingPlayer)
  1367. end
  1368.  
  1369.  
  1370.  
  1371. function chatFunctions.setRank(params) -- chat function to set the rank of a player
  1372. local player = params[1]
  1373. local rank = params[2]
  1374.  
  1375.     if not table.contains(playerNames,player) then
  1376.     return "param #1 is supposed to be a registered player"
  1377.     end
  1378.    
  1379.     if not playerRanks[rank] then
  1380.     return "param #2 is not a viable rank"
  1381.     end
  1382.    
  1383.     if not (isPermLevelHigher(executingPlayer,player) or executingPlayer == player) then
  1384.     return "Your permission level is not high enough to change the rank of this player"
  1385.     end
  1386.    
  1387.     if playerData[player]["rank"] == rank then
  1388.     return "This player already has this rank"
  1389.     end
  1390.    
  1391.     if getPermissionLevel(executingPlayer) <= playerRanks[rank]["permissionLevel"] then
  1392.     return "Your permission level is not high enough to grant this rank"
  1393.     end
  1394.    
  1395.    
  1396. setPlayerRank(player,rank)
  1397. sendMessage("Rank succesfully changed to " .. rank, executingPlayer, "green")
  1398. end
  1399.  
  1400.  
  1401.  
  1402. function chatFunctions.changeSetting(params) -- chat function to change the setting of a player
  1403.  
  1404.  
  1405.     if playerData[params[1]] then
  1406.     player = params[1]
  1407.     setting = params[2]
  1408.     value = params[3]
  1409.     else
  1410.     player = executingPlayer
  1411.     setting = params[1]
  1412.     value = params[2]
  1413.     end
  1414.  
  1415.  
  1416.     if not table.contains(playerNames,player) then
  1417.     return "This player is not registered."
  1418.     end
  1419.    
  1420.     if not settings[setting] then
  1421.     return "This setting does not exist."
  1422.     end
  1423.    
  1424.     if getPermissionLevel(player) < settings[setting]["requiredPermLevl"]  then
  1425.     return "Your permission level is not high enough to change this setting."
  1426.     end
  1427.    
  1428.     if not getPlayerSetting("canChangeOtherPlayersSettings", player) and player ~= executingPlayer then
  1429.     return "You do not have permission to change other players settings."
  1430.     end
  1431.    
  1432.     if player ~= executingPlayer and getPermissionLevel(player) >= getPermissionLevel(executingPlayer) then
  1433.     return "Your permission level is not high enaugh to change this players settings."
  1434.     end
  1435.    
  1436.    
  1437.     if settings[setting]["type"] == "boolean" then
  1438.         if string.lower(value) == "true" then
  1439.         value = true
  1440.         elseif string.lower(value) == "false" then
  1441.         value = false
  1442.         end
  1443.     elseif settings[setting]["type"] == "number" then
  1444.     value = tonumber(value)
  1445.     end
  1446.    
  1447.     if type(value) ~= settings[setting]["type"] then
  1448.     return "bad argument (value has the wrong type, expected type: ".. settings[setting]["type"] ..")"
  1449.     end
  1450.    
  1451.    
  1452.     if executingPlayer == player or (isPermLevelHigher(executingPlayer,player) and getPlayerSetting("canChangeOtherPlayersSettings")) then
  1453.     changeSetting(player,setting,value)
  1454.     sendMessage("The setting was succesfully changed.", executingPlayer, "green")
  1455.     end
  1456.  
  1457. end
  1458.  
  1459.  
  1460.  
  1461. function chatFunctions.help(params) -- chat function that gives the executing player information about the chat commands
  1462. local returnMessage = nil
  1463. local getHelpOnWhat = params[1]
  1464.  
  1465.     if tonumber(getHelpOnWhat) or not getHelpOnWhat then -- checks if a chat command to get information on was specified
  1466.     local sendThisMessage = {}
  1467.     local page = tonumber(getHelpOnWhat) or 1
  1468.     local numberOfCommands = 0
  1469.    
  1470.         if (page-1)*10+1 > table.maxn(chatCommandNames) then
  1471.         sendMessage("This page does not exist.", executingPlayer, "red")
  1472.         return
  1473.         end
  1474.    
  1475.        
  1476.         if page > 1 then
  1477.         table.insert(sendThisMessage, {{text = "\n<<<< Last page", color = "blue", hoverEvent = hoverMessage("shift + click to insert"), insertion = "$@help " .. page-1}})
  1478.         end
  1479.        
  1480.         for k,commandName in pairs(chatCommandNames) do
  1481.             if numberOfCommands >= (page-1)*10 and numberOfCommands < page*10 then
  1482.             local info = chatCommands[commandName]["info"]
  1483.                 if getPermissionLevel(executingPlayer) >= chatCommands[commandName]["requiredPermLevl"] then
  1484.                 table.insert(sendThisMessage,
  1485.                 {"\n",
  1486.                 {text = "@" .. commandName, color = "green", insertion = "$@" .. commandName, hoverEvent = hoverMessage(info .. "\nshift + click to insert")},
  1487.                 {text = " - Required permission level: ", insertion = "$@" .. commandName, hoverEvent = hoverMessage(info .. "\nshift + click to insert")},
  1488.                 {text = chatCommands[commandName]["requiredPermLevl"], color = "green", insertion = "$@" .. commandName, hoverEvent = hoverMessage(info .. "\nshift + click to insert")}})
  1489.                 else
  1490.                 table.insert(sendThisMessage,
  1491.                 {"\n",
  1492.                 {text = "@" .. commandName, color = "red", hoverEvent = hoverMessage("You dont have permission to use this command.")},
  1493.                 {text = " - Required permission level: ", color = "red",hoverEvent = hoverMessage("You dont have permission to use this command.")},
  1494.                 {text = chatCommands[commandName]["requiredPermLevl"], color = "red", hoverEvent = hoverMessage("You dont have permission to use this command.")}})
  1495.                 end
  1496.             end
  1497.         numberOfCommands = numberOfCommands + 1
  1498.         end
  1499.        
  1500.         if (page)*10 < table.maxn(chatCommandNames) then
  1501.         table.insert(sendThisMessage, {{text = "\nNext page >>>>", color = "blue", hoverEvent = hoverMessage("shift + click to insert"), insertion = "$@help " .. page+1}})
  1502.         end
  1503.     sendMessage(combineFormattedMessages(sendThisMessage), executingPlayer)
  1504.     return
  1505.     end
  1506.    
  1507.    
  1508.     if chatCommands[getHelpOnWhat] then
  1509.     sendMessage({"\n", {text = "@" .. getHelpOnWhat .. ": ", color = "green", insertion = "$@" .. getHelpOnWhat, hoverEvent = {action = "show_text",value = "shift + click to insert"}}, {text = chatCommands[getHelpOnWhat]["info"] .. " ", insertion = "$@" .. getHelpOnWhat, hoverEvent = {action = "show_text",value = "shift + click to insert"} }, {text = "Required permission level: " .. chatCommands[getHelpOnWhat]["requiredPermLevl"], color = "green", insertion = "$@" .. getHelpOnWhat, hoverEvent = {action = "show_text",value = "shift + click to insert"}}}, executingPlayer)
  1510.     else
  1511.     return nil
  1512.     end
  1513.        
  1514.    
  1515. end
  1516.  
  1517.  
  1518.  
  1519. function chatFunctions.about(params) -- gives information about many things like ranks or the system
  1520. availableInfo = {
  1521. ["system"] = "Gives you information about the system.",
  1522. ["ranks"] = "Gives you information about all ranks."
  1523. }
  1524.    
  1525. local aboutWhat = params[1]
  1526.  
  1527.     if aboutWhat == nil then
  1528.     local message = {"Available params:"}
  1529.         for infoName,infoDescription in pairs(availableInfo) do
  1530.         table.insert(message, {text = "\n@about ", insertion = "$@about " .. infoName, hoverEvent = hoverMessage(infoDescription .. "\nshift + click to insert")})
  1531.         table.insert(message, {text = infoName, insertion = "$@about " .. infoName, hoverEvent = hoverMessage(infoDescription .. "\nshift + click to insert"), color = "green"})
  1532.         end
  1533.     sendMessage(message, executingPlayer)
  1534.     return
  1535.     end
  1536.  
  1537. aboutWhat = string.lower(aboutWhat)
  1538.  
  1539.     if not availableInfo[aboutWhat] then
  1540.     return "You cant get information about this"
  1541.     end
  1542.  
  1543.  
  1544. _ENV["aboutFunctions"][aboutWhat]()
  1545.  
  1546. end
  1547.  
  1548.  
  1549.  
  1550. function chatFunctions.playtimeScoreboard(params) -- shows the executing player the playtime scoreboard
  1551. showScoreboard("playtime", executingPlayer, params[1], " minutes")
  1552. end
  1553.  
  1554.  
  1555.  
  1556. function chatFunctions.listSettings() -- lists the settings of the executing player
  1557. local message = {}
  1558. local greenOrRed = {[true] = "green", [false] = "red"}
  1559.     for k,settingName in pairs(settingNames) do
  1560.     local settingValue = getPlayerSetting(settingName,executingPlayer)
  1561.     table.insert(message, "\n")
  1562.         if getPermissionLevel(executingPlayer) >= settings[settingName]["requiredPermLevl"] then
  1563.         table.insert(message, {text = settingName .. ": ", color = "green", insertion = "$@changeSetting " .. settingName .. " ", hoverEvent = hoverMessage(settings[settingName]["info"] .. "\nshift + click to change")})
  1564.         table.insert(message, {text = settingValue, hoverEvent = hoverMessage(settings[settingName]["info"] .. "\nshift + click to change")})
  1565.         else
  1566.         table.insert(message, {text = settingName .. ": ", color = "red", hoverEvent = hoverMessage(settings[settingName]["info"] .. "\nYou dont have permission to change this setting.")})
  1567.         table.insert(message, {text = settingValue, hoverEvent = hoverMessage(settings[settingName]["info"] .. "\nYou dont have permission to change this setting.")})
  1568.         end
  1569.     end
  1570.  
  1571. sendMessage(message, executingPlayer)
  1572. end
  1573.  
  1574.  
  1575.  
  1576. function chatFunctions.balance(params) -- tells the executing player what their balance is
  1577. player = params[1] or executingPlayer
  1578.  
  1579.     if not playerData[player] then
  1580.     return "This is not a registered player."
  1581.     end
  1582. sendMessage({"Balance: ", {text = (playerData[player]["stats"]["balance"] or 0) .. "c", color = "green"}}, executingPlayer)
  1583. end
  1584.  
  1585.  
  1586.  
  1587. function chatFunctions.pay(params) -- pays the receiving player the specified amount and removes that amount from the balance of the executing player
  1588. local receivingPlayer = params[1]
  1589. local amount = tonumber(params[2])
  1590.  
  1591.     if not playerData[receivingPlayer] then
  1592.     return "This is not a registered player."
  1593.     end
  1594.  
  1595.     if amount > playerData[executingPlayer]["stats"]["balance"] then
  1596.     return "Your balance is too low."
  1597.     end
  1598.    
  1599.     if amount < 0 then
  1600.     return "You cant pay someon less then zero credits."
  1601.     end
  1602.    
  1603. playerData[receivingPlayer]["stats"]["balance"] = playerData[receivingPlayer]["stats"]["balance"] + amount
  1604. playerData[executingPlayer]["stats"]["balance"] = playerData[executingPlayer]["stats"]["balance"] - amount
  1605. savePlayerData(receivingPlayer, "stats")
  1606. savePlayerData(executingPlayer, "stats")
  1607.  
  1608. updateScoreboard("balance", receivingPlayer)
  1609. updateScoreboard("balance", executingPlayer)
  1610.  
  1611. sendMessage({"You succesfully paid ", receivingPlayer, " ", {text = amount .. "c", color = "green"}, "\n Balance: ", {text = playerData[executingPlayer]["stats"]["balance"] .. "c", color = "green"}}, executingPlayer)
  1612. end
  1613.  
  1614.  
  1615.  
  1616. function chatFunctions.balanceScoreboard(params) -- shows the executing player the balance scoreboard
  1617. showScoreboard("balance", executingPlayer, params[1], "c")
  1618. end
  1619.  
  1620.  
  1621.  
  1622. function chatFunctions.tp(params) -- teleports the executing player to the specified coordinates
  1623. local x,y,z = 0,0,0
  1624.     if table.contains(playerDetector.getOnlinePlayers(),params[1]) then
  1625.         if getPermissionLevel(executingPlayer) > 1 then
  1626.         local playerPos = playerDetector.getPlayerPos(params[1])
  1627.         x = playerPos["x"]
  1628.         y = playerPos["y"]
  1629.         z = playerPos["z"]
  1630.         else
  1631.         return "You can only tp to other players at Member rank or higher."
  1632.         end
  1633.     elseif string.lower(params[1]) == "back" then
  1634.         if not playerData[executingPlayer]["lastTpPos"] then
  1635.         return "You dont have a saved last teleport position."
  1636.         end
  1637.     x = playerData[executingPlayer]["lastTpPos"]["x"]
  1638.     y = playerData[executingPlayer]["lastTpPos"]["y"]
  1639.     z = playerData[executingPlayer]["lastTpPos"]["z"]
  1640.     else
  1641.     x = tonumber(params[1])
  1642.     y = tonumber(params[2])
  1643.     z = tonumber(params[3])
  1644.     end
  1645.  
  1646.     if type(x) ~= "number" then
  1647.     return "The first parameter needs to be either a player or a number."
  1648.     end
  1649.    
  1650.     if type(y) ~= "number" then
  1651.     return "The second parameter needs to be a number."
  1652.     end
  1653.    
  1654.     if type(z) ~= "number" then
  1655.     return "The third parameter needs to be a number."
  1656.     end
  1657.  
  1658.  
  1659. local executingPlayerPos = playerDetector.getPlayerPos(executingPlayer)
  1660. eX = executingPlayerPos["x"]
  1661. eY = executingPlayerPos["y"]
  1662. eZ = executingPlayerPos["z"]
  1663. local droneName = getFreeDrone()
  1664.  
  1665.     if not droneName then
  1666.     sendMessage("There is currently no free drone available.", executingPlayer, "red")
  1667.     return
  1668.     elseif setDroneAction(droneName,"teleportPlayer",{{x=eX,y=eY,z=eZ},{x=x,y=y,z=z}},executingPlayer) then
  1669.     sendMessage("Please stand still until the teleportation is complete.", executingPlayer, "green")
  1670.     playerData[executingPlayer]["lastTpPos"] = {["x"]=eX,["y"]=eY,["z"]=eZ}
  1671.     savePlayerData(executingPlayer,"lastTpPos")
  1672.     end
  1673. end
  1674.  
  1675.  
  1676.  
  1677. function chatFunctions.ban(params) -- bans the specified player
  1678. local player = params[1]
  1679.     if not playerData[player] then
  1680.     return "This is not a registered player."
  1681.     end
  1682.    
  1683.     if playerData[player]["rank"] == "Banned" then
  1684.     return "This player is already banned."
  1685.     end
  1686.  
  1687. banPlayer(player, executingPlayer)
  1688. end
  1689.  
  1690.  
  1691.  
  1692. function chatFunctions.unban(params) -- unbans the specifed player
  1693. local player = params[1]
  1694.     if not playerData[player] then
  1695.     return "This is not a registered player."
  1696.     end
  1697.  
  1698.     if playerData[player]["rank"] ~= "Banned" then
  1699.     return "This player is not banned."
  1700.     end
  1701.  
  1702. unbanPlayer(player, executingPlayer)
  1703. end
  1704.  
  1705.  
  1706.  
  1707. function chatFunctions.giveFeedback(params) -- gives feedback about the system
  1708. local feedback = ""
  1709.     for k,v in pairs(params) do
  1710.     feedback = feedback .. v .. " "
  1711.     end
  1712.    
  1713. table.insert(givenfeedback,{["player"] = executingPlayer, ["feedback"] = feedback, ["date"] = os.date()})
  1714. saveTable(programFolderName .. "/givenfeedback" ,givenfeedback)
  1715. sendMessage("Thank you for giving feedback.", executingPlayer, "green")
  1716. end
  1717.  
  1718. ------------------------------------------------
  1719.  
  1720.  
  1721.  
  1722.  
  1723.  
  1724. -- Other stuff
  1725.  
  1726. function table.contains(inputTable,value) -- checks if the specified table contains a value
  1727.     for k,v in pairs(inputTable) do
  1728.         if v == value then
  1729.         return true
  1730.         end
  1731.     end
  1732. return false
  1733. end
  1734.  
  1735.  
  1736.  
  1737. function saveTable(folderName,inputTable) -- saves the specifed table in files inside of the specified folder
  1738. fs.delete(folderName)
  1739. local file = false
  1740.  
  1741.     for k,v in pairs(inputTable) do
  1742.         if type(v) ~= "table" and type(v) ~= "function" then
  1743.             if not file then
  1744.             file = fs.open(folderName .. "/variables","w")
  1745.             end
  1746.            
  1747.             vType = type(v)
  1748.                 if vType == "boolean" then
  1749.                     if v then
  1750.                     v = "true"
  1751.                     else
  1752.                     v = "false"
  1753.                     end
  1754.                 end
  1755.        
  1756.         file.writeLine(k .. string.sub(type(k),1,1) .. "=" .. string.sub(vType,1,1) .. v)
  1757.         elseif type(v) == "table" then
  1758.         saveTable(folderName .. "/" .. k,v)
  1759.         end
  1760.     end
  1761.  
  1762.     if file then
  1763.     file.flush()
  1764.     file.close()
  1765.     end
  1766. end
  1767.  
  1768.  
  1769.  
  1770. function readFile(fileName) -- reads a file created by the save table function and returns the saved table
  1771. local file = fs.open(fileName,"r")
  1772. local returnTable = {}
  1773.  
  1774.     if not file then
  1775.     return {}
  1776.     end
  1777.    
  1778.    
  1779.     repeat
  1780.     local curLine = file.readLine()
  1781.     local equalPos = string.find(curLine or "","=")
  1782.    
  1783.    
  1784.         if equalPos then
  1785.         local indexType = string.sub(curLine,equalPos-1,equalPos-1)
  1786.         local valueType = string.sub(curLine,equalPos+1,equalPos+1)
  1787.         local index = string.sub(curLine,1,equalPos-2)
  1788.        
  1789.             if indexType == "n" then
  1790.             index = tonumber(index)
  1791.             elseif indexType == "b" then
  1792.                 if index == "true" then
  1793.                 index = true
  1794.                 else
  1795.                 index = false
  1796.                 end
  1797.             end
  1798.            
  1799.         local value = string.sub(curLine,equalPos+2)
  1800.             if valueType == "n" then
  1801.             value = tonumber(value)
  1802.             elseif valueType == "b" then
  1803.                 if value == "true" then
  1804.                 value = true
  1805.                 else
  1806.                 value = false
  1807.                 end
  1808.             end
  1809.         returnTable[index] = value
  1810.         end
  1811.        
  1812.     until not curLine
  1813. file.close()
  1814.    
  1815.    
  1816. return returnTable
  1817. end
  1818.  
  1819.  
  1820.  
  1821. function readFolder(folderName)-- reads a folder created by the save table function and returns the saved table
  1822. if not fs.isDir(folderName) then
  1823. return {}
  1824. end
  1825.  
  1826.  
  1827. local returnTable = {}
  1828.  
  1829.     for k,v in pairs(fs.list(folderName)) do
  1830.         if fs.isDir(folderName .. "/" .. v) then
  1831.             if tonumber(v) then
  1832.             key = tonumber(v)
  1833.             elseif v == "true" or v == "false" then
  1834.             key = v == "true"
  1835.             else
  1836.             key = v
  1837.             end
  1838.            
  1839.         returnTable[key] = readFolder(folderName .. "/" .. v)
  1840.         else
  1841.             for k2,v2 in pairs(readFile(folderName .. "/" .. v)) do
  1842.             returnTable[k2] = v2
  1843.             end
  1844.         end
  1845.     end
  1846.    
  1847.  
  1848. return returnTable
  1849. end
  1850.  
  1851. -------------------------------------------------
  1852.  
  1853. noError, errorMessage = pcall(startup)
  1854.  
  1855.  
  1856.     if noError then
  1857.     noError, errorMessage = pcall(main)
  1858.     end
  1859.    
  1860.     if errorMessage ~= "Terminated" then
  1861.    
  1862.     print(noError)
  1863.     print(errorMessage)
  1864.     local curDate = string.gsub(os.date(),":",".")
  1865.     local file = fs.open("crashReports/" .. curDate,"w")
  1866.     file.write(errorMessage)
  1867.     file.flush()
  1868.     file.close()
  1869.  
  1870.     term.setTextColor(colors.red)
  1871.     print("REBOOTING")
  1872.     sleep(10)
  1873.     os.reboot()
  1874.     end
  1875.  
Add Comment
Please, Sign In to add comment