Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- [ --------------------------------------------------------------------- ] --
- -- [ RedNetChat - A public chat program for ComputerCraft ] --
- -- [ Created by gpgautier (ign gpgauier), 2012 ] --
- -- [ Licence: Creative Commons Attribution-ShareAlike 3.0 Unported License ] --
- -- [ ComputerCraft version: 1.3 and up ] --
- -- [ Posted to: ] --
- -- [ GitHub: https://github.com/gpgautier/RedNetChat ] --
- -- [ Pastebin: http://pastebin.com/JDU4wJxX ] --
- -- [ --------------------------------------------------------------------- ] --
- local VERSION = "0.6"
- local MODEM = nil
- local NICKNAME = nil
- local ACTIVE = false
- local BUFFER = {}
- local POINTER = 0
- local ONLINE = {}
- local ISONLINE = false
- local ID = os.computerID()
- local LAST_MSG_TARGET = nil
- local CHANNEL = 1
- local SCROLL_POINTER = POINTER
- local WIDTH, HEIGHT = term.getSize()
- local LINES = HEIGHT - 6
- local START_LINE = 5
- local OPERATOR = "RNC"
- -- [ --------------------------------------------------------------------- ] --
- -- Split a string
- function split(str, pat)
- local t = {} -- NOTE: use {n = 0} in Lua-5.0
- if str ~= nil then
- local fpat = "(.-)" .. pat
- local last_end = 1
- local s, e, cap = str:find(fpat, 1)
- while s do
- if s ~= 1 or cap ~= "" then
- table.insert(t,cap)
- end
- last_end = e+1
- s, e, cap = str:find(fpat, last_end)
- end
- if last_end <= #str then
- cap = str:sub(last_end)
- table.insert(t, cap)
- end
- else
- print("##ERROR failed to split ["..str.."] by:"..pat)
- end
- return t
- end
- -- Log a message to file
- function log(message)
- local file = io.open("rednetchat.log", "a")
- file:write("\n" .. message)
- file:close()
- end
- -- Application entry
- function main()
- term.clear()
- term.setCursorPos(1, 1)
- if not setPeripherals() then
- print("[FATAL ERROR] Not able to setup peripherals.")
- return false
- end
- welcome()
- end
- -- Set the attached peripherals. Opens rednet modem and warps monitor
- function setPeripherals()
- local i, side
- for i, side in pairs(rs.getSides()) do
- if peripheral.isPresent(side) then
- if peripheral.getType(side) == "modem" then
- MODEM = side
- if not rednet.isOpen(side) then
- rednet.open(MODEM)
- end
- end
- end
- end
- -- Exit with a fatal error when modem not found
- if MODEM == nil then
- print("[FATAL ERROR] No modem was detected. Plase attach a modem on any side.")
- return false
- end
- return true
- end
- -- Start the welcome screen
- function welcome()
- local x, y
- term.clear()
- writeHeader()
- print("")
- print("")
- print("Enter a nickname and press [enter].")
- print("")
- term.write("Nickname: ")
- x, y = term.getCursorPos()
- while NICKNAME == nil or NICKNAME == "" do
- term.setCursorPos(x, y)
- NICKNAME = read()
- execute("/online")
- appendBuffer("[" .. OPERATOR .. "]: Type /help for a list of commands")
- end
- start()
- end
- -- Writes the screen header
- function writeHeader()
- local col
- term.setCursorPos(1, 1)
- term.write("RedNet Chat " .. VERSION .. "")
- term.setCursorPos(1, 2)
- for col = 1, WIDTH do
- term.write("-")
- end
- end
- -- Writes the list of online users
- function writeOnlineList()
- local i, v, count, x, y, col
- count = 0
- x, y = term.getCursorPos()
- term.setCursorPos(1, HEIGHT - 1)
- for col = 1, WIDTH do
- term.write("-")
- end
- term.setCursorPos(1, HEIGHT)
- term.clearLine()
- term.write("Online: ")
- for i, v in pairs(ONLINE) do
- if count == 0 then
- term.write(i)
- else
- term.write(", " .. i)
- end
- count = count + 1
- end
- if count == 0 then
- term.write("Nobody online in channel " .. CHANNEL)
- end
- term.setCursorPos(x, y)
- end
- -- Start the chat
- function start()
- term.clear()
- writeHeader()
- writeOnlineList()
- ACTIVE = true
- showBuffer()
- parallel.waitForAll(input, watchEvents)
- end
- -- Stop the application
- function stop()
- ACTIVE = false
- end
- -- Reset the application
- function reset()
- execute("/offline")
- if rednet.isOpen(MODEM) then
- rednet.close(MODEM)
- end
- sleep(1.5)
- os.reboot()
- end
- -- Watch all input to provide possible shortcuts (for example usernames)
- function watchEvents()
- local type, param, param2, param3, i, v
- while ACTIVE do
- type, param, param2, param3 = os.pullEvent()
- if type == "key" then
- if param == 200 then -- up
- scroll(-1)
- elseif param == 208 then -- down
- scroll(1)
- elseif param == 201 then -- pageup
- scroll(-12)
- elseif param == 209 then -- pagedown
- scroll(12)
- --else
- -- appendBuffer(tostring(param))
- end
- elseif type == "mouse_scroll" then
- if param == -1 then
- scroll(-1)
- else
- scroll(1)
- end
- elseif type == "rednet_message" then
- receive(param2)
- end
- end
- end
- -- Scroll through the chat
- function scroll(amount)
- SCROLL_POINTER = SCROLL_POINTER + amount
- showBuffer()
- end
- -- Handle input from the prompt
- function input()
- local message, col
- term.setCursorPos(1, 4)
- for col = 1, WIDTH do
- term.write("-")
- end
- while ACTIVE do
- term.setCursorPos(1, 3)
- term.clearLine()
- term.write("[" .. CHANNEL .. "] > ")
- message = read()
- if message ~= nil and message ~= "" then
- execute(message, "local")
- end
- end
- end
- -- Send a message
- function send(message, target)
- local request, serialized, x, encrypted
- request = {protocol = "rnc", nickname = NICKNAME, sender = ID, target = target, channel = CHANNEL, message = message}
- serialized = textutils.serialize(request)
- encrypted = ""
- for x = 1, #serialized do
- encrypted = encrypted .. string.char(serialized:byte(x) + 1)
- end
- if request.target ~= nil then
- rednet.send(request.target, encrypted)
- else
- rednet.broadcast(encrypted)
- end
- end
- -- Recieve a message
- function receive(message)
- local request, decrypted, x
- if message ~= nil and message ~= "" then
- decrypted = ""
- for x = 1, #message do
- decrypted = decrypted .. string.char(message:byte(x) - 1)
- end
- request = textutils.unserialize(decrypted)
- if request.protocol == "rnc" and request.channel == CHANNEL then
- if request.nickname ~= nil and request.nickname ~= "" then
- execute(request, "remote")
- end
- end
- end
- end
- -- Execute a command or add a chat message
- function execute(message, source)
- local command, splitCommand, nickname, id, body, onlineUser
- if message.nickname ~= nil then
- executeRemote(message)
- return
- end
- if message:sub(0, 1) == "/" then
- command = message:sub(2)
- if command == "quit"
- or command == "reset"
- or command == "restart"
- or command == "reboot"
- or command == "stop"
- then
- appendBuffer("[" .. OPERATOR .. "]: Stopping application")
- reset()
- elseif command == "online" then
- if not ISONLINE then
- send("/online")
- putOnline()
- appendBuffer("[" .. OPERATOR .. "]: You are now online")
- ISONLINE = true
- else
- appendBuffer("[" .. OPERATOR .. "]: You are already online")
- end
- elseif command == "offline" then
- if ISONLINE then
- send("/offline")
- takeOffline()
- appendBuffer("[" .. OPERATOR .. "]: You are now offline")
- ISONLINE = false
- else
- appendBuffer("[" .. OPERATOR .. "]: You are already offline")
- end
- elseif command:sub(0, 5) == "nick " then
- takeOffline()
- NICKNAME = command:sub(6)
- putOnline()
- appendBuffer("[" .. OPERATOR .. "]: Your nickname has been changed")
- elseif command:sub(0, 5) == "slap " then
- appendBuffer(command:sub(6) .. " was slapped by " .. NICKNAME)
- elseif command:sub(0, 4) == "msg " then
- splitCommand = split(command:sub(5), "%s")
- onlineUser = false
- for nickname, id in pairs(ONLINE) do
- if nickname == splitCommand[1] then
- body = command:sub(5 + splitCommand[1]:len() + 1)
- send(body, id)
- appendBuffer(NICKNAME .. " > " .. nickname .. ": " .. body)
- onlineUser = true
- LAST_MSG_TARGET = nickname
- end
- end
- if not onlineUser then
- appendBuffer("[" .. OPERATOR .. "]: User " .. splitCommand[1] .. " is not online")
- end
- elseif command:sub(0, 2) == "r " then
- if LAST_MSG_TARGET ~= nil then
- execute("/msg " .. LAST_MSG_TARGET .. " " .. command:sub(3), "local")
- else
- appendBuffer("[" .. OPERATOR .. "]: No valid user for message")
- end
- elseif command:sub(0, 5) == "join " then
- if CHANNEL ~= tonumber(command:sub(6)) then
- execute("/offline")
- CHANNEL = tonumber(command:sub(6))
- execute("/online")
- appendBuffer("[" .. OPERATOR .. "]: Joined channel " .. CHANNEL)
- else
- appendBuffer("[" .. OPERATOR .. "]: Already in channel " .. CHANNEL)
- end
- elseif command == "help" then
- appendBuffer("[" .. OPERATOR .. "] Commands:")
- appendBuffer("/quit : Exit the chat")
- appendBuffer("/msg <nickname> <message> : Send a private message")
- appendBuffer("/r <message> : Reply to a private message")
- appendBuffer("/join <channel> : Switch channel")
- else
- appendBuffer("[" .. OPERATOR .. "]: Unknown command")
- end
- return
- end
- appendBuffer(NICKNAME .. ": " .. message)
- send(message)
- end
- --
- function putOnline(nickname, id)
- if nickname == nil or id == nil then
- nickname = NICKNAME
- id = ID
- end
- ONLINE[nickname] = id
- writeOnlineList()
- end
- --
- function takeOffline(nickname, id)
- if nickname == nil or id == nil then
- nickname = NICKNAME
- id = ID
- end
- ONLINE[nickname] = nil
- writeOnlineList()
- end
- --
- function executeRemote(request)
- local command
- if request.message:sub(0, 1) == "/" then
- command = request.message:sub(2)
- if command == "online" then
- putOnline(request.nickname, request.sender)
- appendBuffer("[" .. OPERATOR .. "]: " .. request.nickname .. " is now online")
- send("/metoo")
- elseif command == "offline" then
- takeOffline(request.nickname, request.sender)
- appendBuffer("[" .. OPERATOR .. "]: " .. request.nickname .. " is now offline")
- elseif command == "metoo" then
- putOnline(request.nickname, request.sender)
- end
- return
- end
- if request.target ~= nil then
- appendBuffer(request.nickname .. " > " .. NICKNAME .. ": " .. request.message)
- LAST_MSG_TARGET = request.nickname
- else
- appendBuffer(request.nickname .. ": " .. request.message)
- end
- end
- --
- function appendBuffer(message)
- local length
- length = message:len()
- if length > WIDTH then
- table.insert(BUFFER, message:sub(1, WIDTH))
- POINTER = POINTER + 1
- appendBuffer(message:sub(WIDTH + 1))
- else
- table.insert(BUFFER, message)
- POINTER = POINTER + 1
- end
- SCROLL_POINTER = POINTER
- showBuffer()
- end
- --
- function showBuffer()
- local i, line, bufferPointer, x, y, pointer
- pointer = SCROLL_POINTER
- if pointer == 0 then
- return
- elseif SCROLL_POINTER > POINTER then
- SCROLL_POINTER = POINTER
- pointer = POINTER
- elseif POINTER < LINES + 1 then
- SCROLL_POINTER = POINTER
- pointer = POINTER
- elseif POINTER > LINES and SCROLL_POINTER < LINES then
- SCROLL_POINTER = LINES
- pointer = SCROLL_POINTER
- end
- x, y = term.getCursorPos()
- line = START_LINE
- bufferPointer = -(LINES - 1 - pointer)
- for i = bufferPointer, bufferPointer + (LINES - 1) do
- term.setCursorPos(1, line)
- term.clearLine()
- if BUFFER[i] ~= nil then
- term.write(tostring(BUFFER[i]))
- end
- line = line + 1
- end
- term.setCursorPos(x, y)
- end
- -- Fire up the application
- main()
Add Comment
Please, Sign In to add comment