Chaos_Cash

serverHelper.lua

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