Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Chat Assistant
- print("1lann's Chat Assistant Central Server")
- print("Please don't touch me :(")
- local chat = peripheral.wrap("right")
- local modem = peripheral.wrap("top")
- local drive = peripheral.wrap("left")
- local operatingChannel = 27158
- local successChannel = 27159
- if not chat then
- error("Could not find chatbox!")
- end
- if modem then
- modem.closeAll()
- modem.open(successChannel)
- print("Modem ready")
- else
- print("Warning: No modem found")
- end
- if drive then
- print("Disk drive detected")
- if drive.getAudioTitle() then
- print("Loaded with disk: "..drive.getAudioTitle())
- drive.stopAudio()
- else
- print("No music disk found!")
- end
- else
- print("No disk drive detected")
- end
- local database = {}
- local localDatabase = {}
- local messageQueue = {}
- local pendingReminders = {}
- local musicLength = 190
- local musicClock = musicLength * -1
- local successCalls = {}
- local orderedKeys = {}
- local searchAndTrim = function(message, searches, limit)
- if not limit then
- limit = #message + 1
- end
- for k, v in pairs(searches) do
- local startPos, endPos = message:lower():find(v)
- local match = nil
- local err, msg = pcall(function() match = message:lower():match(v) end)
- if endPos and startPos <= limit then
- if err then
- return true, message:sub(endPos, -1), {match}, startPos
- else
- return true, message:sub(endPos, -1), {}, startPos
- end
- end
- end
- return false, message
- end
- local saveDatabase = function()
- local f = io.open("/chat-config", "w")
- f:write(textutils.serialize(database))
- f:close()
- end
- local commands = {}
- commands["remind"] = function(time, units, player, message)
- if time ~= nil and time > 0 then
- if not database[player] then
- database[player] = {}
- end
- if not database[player].reminders then
- database[player].reminders = {}
- end
- if #database[player].reminders >= 3 then
- return true, {"Sorry, I can only store 3 reminders at once.", "To cancel a reminder, you can \"cancel reminder\" it"}
- end
- if units == "sec" then
- table.insert(database[player].reminders, {message, os.clock() + time})
- saveDatabase()
- return true, {"Okay, I will remind you in " .. time .. " seconds.", "Use \"cancel reminder\" to cancel your reminder"}
- else
- table.insert(database[player].reminders, {message, os.clock() + time*60})
- saveDatabase()
- return true, {"Okay, I will remind you in " .. time .. " minutes.", "Use \"cancel reminder\" to cancel your reminder"}
- end
- else
- return true, {"Sorry, I couldn't understand", "when you wanted to be reminded :("}
- end
- end
- local matches = {}
- matches["1remind"] = function(player, message)
- if searchAndTrim(message, {" in %d+"}, 3) then
- local _, search = searchAndTrim(message, {" in %d"}, 3)
- local secSuccess, secSearch, secMatch = searchAndTrim(search, {"(%d+) secs,? ", "(%d+) sec,? ", "(%d+) seconds,? ", "(%d+) second,? "}, 3)
- local minSuccess, minSearch, minMatch = searchAndTrim(search, {"(%d+) min,? ", "(%d+) minute,? ", "(%d+) minutes,? ", "(%d+)mins,? "}, 3)
- if secSuccess then
- local remindSuccess, search = searchAndTrim(secSearch, {" remind me ", " reminder "}, 8)
- if remindSuccess then
- _, search = searchAndTrim(search, {" to "}, 12)
- return commands.remind(tonumber(secMatch[1]), "sec", player, search:sub(2, -1))
- end
- elseif minSuccess then
- local remindSuccess, search = searchAndTrim(minSearch, {" remind me ", " reminder "}, 8)
- if remindSuccess then
- _, search = searchAndTrim(search, {" to "}, 12)
- return commands.remind(tonumber(minMatch[1]), "min", player, search:sub(2, -1))
- end
- end
- elseif searchAndTrim(message, {" remind me ", " reminder "}, 10) then
- if searchAndTrim(message, {" cancel "}, 10) then
- return
- end
- local _, search = searchAndTrim(message, {" remind me ", " reminder "})
- local secSuccess, secSearch, secMatch = searchAndTrim(search, {" in (%d+) secs,? ", " in (%d+) sec,? ", " in (%d+) seconds,? ", " in (%d+) second,? "}, 3)
- local minSuccess, minSearch, minMatch = searchAndTrim(search, {" in (%d+) min,? ", " in (%d+) minute,? ", " in (%d+) minutes,? ", " in (%d+)mins,? "}, 3)
- if secSuccess then
- _, search = searchAndTrim(secSearch, {" to "}, 12)
- return commands.remind(tonumber(secMatch[1]), "sec", player, search:sub(2, -1))
- elseif minSuccess then
- _, search = searchAndTrim(minSearch, {" to "}, 12)
- return commands.remind(tonumber(minMatch[1]), "min", player, search:sub(2, -1))
- else
- local searchSuccess, search = searchAndTrim(search, {" to "}, 12)
- if searchSuccess then
- local secSuccess, _, secMatch, secStart = searchAndTrim(search, {" in (%d+) secs", " in (%d+) sec", " in (%d+) seconds", " in (%d+) second"})
- local minSuccess, _, minMatch, minStart = searchAndTrim(search, {" in (%d+) min", " in (%d+) minute", " in (%d+) minutes", " in (%d+)mins"})
- if secSuccess then
- return commands.remind(tonumber(secMatch[1]), "sec", player, search:sub(2, secStart - 1))
- elseif minSuccess then
- return commands.remind(tonumber(minMatch[1]), "min", player, search:sub(2, minStart - 1))
- else
- return true, {"Sorry, I couldn't understand", "when you wanted to be reminded :("}
- end
- else
- return true, {"Sorry, I couldn't understand", "when you wanted to be reminded :("}
- end
- end
- end
- end
- matches["cancel-reminder"] = function(player, message)
- if searchAndTrim(message, {" cancel reminder", " dismiss reminder", " delete reminder"}) then
- if database[player] and database[player].reminders then
- if #database[player].reminders < 1 then
- return true, {"You don't have any reminders set!"}
- elseif #database[player].reminders == 1 then
- local reminderText = database[player].reminders[1][1]
- table.remove(database[player].reminders, 1)
- saveDatabase()
- return true, {"Alright, your reminder:", reminderText, "has been cancelled."}
- else
- local _, search = searchAndTrim(message, {" cancel reminder", " dismiss reminder"})
- if searchAndTrim(search, {"%d+"}) then
- local _, _, match = searchAndTrim(search, {"(%d+)"})
- if tonumber(match[1]) <= #database[player].reminders then
- local reminderText = database[player].reminders[tonumber(match[1])][1]
- table.remove(database[player].reminders, tonumber(match[1]))
- saveDatabase()
- return true, {"Alright, your reminder:", reminderText, "has been cancelled."}
- else
- return true, {"Sorry, I could not find that reminder index!"}
- end
- end
- local returnTable = {}
- table.insert(returnTable, "Here are your active reminders: ")
- for k,v in pairs(database[player].reminders) do
- table.insert(returnTable, "#"..tostring(k)..": "..v[1])
- end
- table.insert(returnTable, "What reminder number would you like to cancel?")
- table.insert(returnTable, "You can append \"#\" or \"number\" as a prefix")
- return true, returnTable
- end
- end
- elseif #localDatabase[player] > 0 and localDatabase[player][#localDatabase[player]][1] == "cancel-reminder" then
- if searchAndTrim(message, {"^%d+", "^# ?%d+", "^number ?%d+"}) then
- local _, _, match = searchAndTrim(message, {"(%d+)"})
- if tonumber(match[1]) <= #database[player].reminders then
- local reminderText = database[player].reminders[tonumber(match[1])][1]
- table.remove(database[player].reminders, tonumber(match[1]))
- saveDatabase()
- return true, {"Alright, your reminder:", reminderText, "has been cancelled."}, true
- else
- return true, {"Sorry, I could not find that reminder index!"}
- end
- end
- end
- end
- matches["list-reminders"] = function(player, message)
- if searchAndTrim(message, {" what reminders? ", " what are my %S* ?reminder", " list reminder"}) then
- if database[player] and database[player].reminders then
- if #database[player].reminders < 1 then
- return true, {"You currently have no set reminders!"}
- elseif #database[player].reminders == 1 then
- return true, {"You have 1 active reminder:", database[player].reminders[1][1], "Use \"cancel reminder\" to cancel a reminder"}
- else
- local returnTable = {}
- table.insert(returnTable, "Your active reminders: ")
- for k,v in pairs(database[player].reminders) do
- table.insert(returnTable, "#"..k..": "..v[1])
- end
- table.insert(returnTable, "Use \"cancel reminder\" to cancel a reminder")
- return true, returnTable
- end
- end
- end
- end
- matches["compliment"] = function(player, message)
- if #localDatabase[player] > 0 and (os.clock() - localDatabase[player][#localDatabase[player]][2]) < 30 then
- if searchAndTrim(message, {"thank", "kudo", "cool", "nice", "wow", "awesome"}) then
- return true, {"If that was a compliment directed", "towards me, Thank you! :D"}
- end
- end
- end
- matches["time"] = function(player, message)
- if searchAndTrim(message, {" what ", " whats ", " what's ", " what is "}) then
- local _, search = searchAndTrim(message, {" what ", " whats ", " what's ", " what is "})
- if searchAndTrim(search, {" time"}, 15) then
- _, search = searchAndTrim(search, {" time"}, 15)
- if searchAndTrim(search, {" for ", " in "}, 8) then
- return true, {"Sorry, I cannot provide location based time,", "I can only provide in game time"}
- else
- return true, {"The current in-game time is " .. textutils.formatTime(os.time())}
- end
- end
- end
- end
- matches["help"] = function(player, message)
- if #localDatabase[player] > 0 and (os.clock() - localDatabase[player][#localDatabase[player]][2]) < 30 then
- if searchAndTrim(message, {" what is this", " whats that", " what's that", " what is chat", " what's chat", " what are you"}) then
- return true, {"Hello there, I'm Chat Assistant!",
- "I'm made by 1lann and am still in",
- "development. Anyways, thanks",
- "for trying me out! :D"}
- end
- end
- end
- matches["1stopwatch"] = function(player, message)
- if searchAndTrim(message, {" start stopwatch", " start counting", " stopwatch start", " start the stopwatch"}) then
- localDatabase[player].stopwatch = {}
- localDatabase[player].stopwatch.running = true
- localDatabase[player].stopwatch.start = os.clock()
- return true, {"Alright, I have started the stopwatch."}
- elseif searchAndTrim(message, {" stop stopwatch", " quit stopwatch", " stop counting", " quit counting",
- " stop the stopwatch", " quit the stopwatch", " stopwatch stop", " stopwatch end", " stopwatch quit",
- " end counting", " end stopwatch"}) then
- if localDatabase[player].stopwatch then
- if localDatabase[player].stopwatch.running then
- localDatabase[player].stopwatch.running = false
- localDatabase[player].stopwatch.start = os.clock() - localDatabase[player].stopwatch.start
- local reading = math.ceil(localDatabase[player].stopwatch.start*100 - 0.5)/100
- return true, {"Okay, I stopped the stopwatch", "The stopwatch reads: "..reading.." seconds"}
- else
- local reading = math.ceil(localDatabase[player].stopwatch.start*100 - 0.5)/100
- return true, {"The stopwatch has already been stopped", "The stopwatch reads: "..reading.." seconds"}
- end
- else
- end
- elseif searchAndTrim(message, {" how much time", " stopwatch", " time passed"}) then
- if localDatabase[player].stopwatch then
- if localDatabase[player].stopwatch.running then
- local rawReading = os.clock() - localDatabase[player].stopwatch.start
- local reading = math.ceil(rawReading*100 - 0.5)/100
- return true, {"The running stopwatch reads: "..reading.." seconds"}
- else
- local reading = math.ceil(localDatabase[player].stopwatch.start*100 - 0.5)/100
- return true, {"The stopped stopwatch reads: "..reading.." seconds"}
- end
- else
- return true, {"You have never started the stopwatch!"}
- end
- end
- end
- local alphabet = "abcdefghijklmnopqrstuvwxyz"
- matches["math"] = function(player, message)
- local matchSuccess, _, search = searchAndTrim(message, {" what's (%(*%d.+)$", " what is (%(*%d.+)$", " whats (%(*%d.+)$", "^%S+ (%(*%d.+)$", "^(%(*%d.+)$", " what does (%(*%d.+)$", " what is (%(*%d.+)$"})
- if matchSuccess then
- search = search[1]
- end
- if matchSuccess and (search:find("%+") or search:find("%*") or search:find("%^") or search:find("%/") or search:find("%-")) then
- search = search:gsub("?", "")
- search = search:gsub("=", "")
- for i = 1, #alphabet do
- search = search:gsub(alphabet:sub(i, i), "")
- end
- local func = loadstring("return "..search)
- local result = nil
- if func then
- if pcall(function() result = func() end) then
- return true, {"The answer is: "..tostring(result)}
- else
- return true, {"Sorry, I couldn't calculate that!", "Make sure you don't use any", "alphabetical letters in it"}
- end
- else
- return true, {"Sorry, I couldn't process that calculation!", "Make sure you don't use any", "alphabetical letters in it"}
- end
- end
- end
- matches["1music"] = function(player, message)
- if searchAndTrim(message, {" play ", " listen to "}) then
- local _, search = searchAndTrim(message, {" play ", " listen to ", " start "})
- if drive then
- if searchAndTrim(search, {" music", " some music", " song", " some song", " the music", " the song", tostring(drive.hasAudio())}, 3) then
- if drive.getAudioTitle() and (os.clock() - musicClock) < musicLength then
- return true, {"Music is already playing!"}, false, true
- elseif drive.getAudioTitle() then
- return true, {"Now playing: "..drive.getAudioTitle()}, false, true, function()
- musicClock = os.clock()
- drive.playAudio()
- end
- else
- return true, {"I don't have any music in", "my disk drive to play :("}, false, true
- end
- else
- return true, {"Sorry, I currently can only play", "the disk in my disk drive :("}
- end
- else
- return true, {"Sorry, I don't have a disk drive", "to play music with :("}, false, true
- end
- elseif searchAndTrim(message, {" what ", " whats ", " what's ", " what is "}) then
- local _, search = searchAndTrim(message, {" what ", " whats ", " what's ", " what is "})
- if searchAndTrim(search, {" song", " this song", " the song", " music", " this music", " playing", " the music", " the current song", " this current song", " currently play"}, 3) then
- if drive and drive.getAudioTitle() and (os.clock() - musicClock) < musicLength then
- return true, {"The currently playing song is", drive.getAudioTitle()}
- else
- return true, {"There currently is no music playing!"}, false, true
- end
- end
- elseif searchAndTrim(message, {" stop ", " pause "}) then
- local _, search = searchAndTrim(message, {" stop ", " pause "})
- if searchAndTrim(search, {" play", " music", " the music", " the song", " this music", " this song"}, 3) then
- if drive and drive.getAudioTitle() and (os.clock() - musicClock) < musicLength then
- return true, {"Ok, music stopped"}, false, true, function()
- drive.stopAudio()
- musicClock = musicLength * -1
- end
- else
- return true, {"There currently is no music playing!"}, false, true
- end
- end
- end
- end
- if fs.exists("/chat-config") then
- local f = io.open("/chat-config")
- database = textutils.unserialize(f:read("*a"))
- f:close()
- end
- if database then
- print("Database loaded!")
- else
- database = {}
- print("Database failed to be loaded!")
- end
- print("Running chat assistant")
- local tell = function(player, messages, successCallback, localAction)
- table.insert(messageQueue, {player, "---- Chat Assistant ----", successCallback, localAction})
- for k,v in pairs(messages) do
- table.insert(messageQueue, {player, v, nil, localAction})
- end
- end
- for k,v in pairs(database) do
- if v.reminders and #v.reminders > 0 then
- for i = 1, #v.reminders do
- database[k].reminders[i][2] = 0
- end
- end
- end
- local checkTimer = os.startTimer(1)
- local success, messages, clear, localAction, callbackFunc = nil, nil, nil, nil, nil
- local function mainLoop()
- while true do
- local e, side, player, message = os.pullEvent()
- if e == "chat_message" or e == "chatbox_command" then
- if message:sub(1, 2) == "$$" then
- message = message:sub(3, -1)
- end
- message = " " .. message
- if not localDatabase[player] then
- localDatabase[player] = {}
- end
- if message == "cancel" then
- table.insert(localDatabase[player], {"clear", os.clock()})
- end
- for _, key in pairs(orderedKeys) do
- local err, msg = pcall(function() success, messages, clear, localAction, callbackFunc = matches[key](player, message) end)
- if not err then
- print("An error has occured while running: "..key)
- print(msg)
- else
- if success then
- tell(player, messages, callbackFunc, localAction)
- if clear then
- table.insert(localDatabase[player], {"clear", os.clock()})
- else
- table.insert(localDatabase[player], {key, os.clock()})
- end
- break
- end
- end
- success, messages, clear, localAction, callbackFunc = nil, nil, nil, nil
- end
- elseif e == "timer" and side == checkTimer then
- checkTimer = os.startTimer(1)
- for k,v in pairs(database) do
- if v.reminders and #v.reminders > 0 then
- for i = 1, #v.reminders do
- if v.reminders[#v.reminders - i + 1] and os.clock() >= v.reminders[#v.reminders - i + 1][2] then
- if (not pendingReminders[tostring(#v.reminders - i + 1)]) or pendingReminders[tostring(#v.reminders - i + 1)] < os.clock() then
- pendingReminders[tostring(#v.reminders - i + 1)] = os.clock() + 5
- tell(k, {"Reminder: " .. v.reminders[#v.reminders - i + 1][1]},
- function()
- pendingReminders[tostring(#v.reminders - i + 1)] = nil
- table.remove(database[k].reminders, #v.reminders - i + 1)
- saveDatabase()
- end)
- end
- end
- end
- end
- end
- end
- end
- end
- local function sendLoop()
- while true do
- sleep(0.6)
- if #messageQueue > 0 then
- local result = nil
- while not pcall(function() result = chat.tell(messageQueue[1][1], messageQueue[1][2]) end) do
- sleep(0.2)
- end
- if result then
- if messageQueue[1][3] then
- local err, msg = pcall(messageQueue[1][3])
- if not err then
- print("Error while running callback")
- print(msg)
- end
- end
- elseif modem and not messageQueue[1][4] then
- local newID = tostring({}):sub(8, -1)
- if messageQueue[1][3] then
- successCalls[newID] = messageQueue[1][3]
- end
- modem.transmit(operatingChannel, operatingChannel, {
- "chat-assistant-network", newID, messageQueue[1][1], messageQueue[1][2]
- })
- end
- table.remove(messageQueue, 1)
- end
- end
- end
- local function receiveLoop()
- while true do
- local event, side, channel, reply, message = os.pullEvent()
- if event == "modem_message" and channel == successChannel and type(message) == "string" then
- if successCalls[message] then
- local err, msg = pcall(successCalls[message])
- if not err then
- print("Error while running remote callback")
- print(msg)
- end
- successCalls[message] = nil
- end
- end
- end
- end
- for k in pairs(matches) do
- table.insert(orderedKeys, k)
- end
- table.sort(orderedKeys)
- parallel.waitForAny(mainLoop, sendLoop, receiveLoop)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement