This is a little program I made when I decided to take a little break from working on my OS (wich will be updated soon). It's a chat program that let's you chat (obviously) with everyone who are connected. It doesn't require a server, it connects to everyone in range.
Features:
* Easy to use and configure.
* Easy to add functionality.
* Works with modems and bundled cable (although not recomended).
* Opens connection on every side so you don't have to choose wich one to use.
* Chat history (with configurable maximum size).
How to use:
Just install the program and run it. It will ask your name, and when you enter a valid name it connects to let you chat. Just type any message and press enter to send it. You can go through the chat history with the up/down arrow keys to see messages out of the screen. When you want to exit, just press Ctrl to open the menu and press enter (Exit is the only menu option).
How to Install:
- Get the code at the end of the post or from pastebin (you can use the pastebin program, code: q13Pv8JD)
- Save it to a file on the computer.
- Change any configuration options you want (at the start of the file)
- That's it, enjoy :D/>/>
Feel free to modify it in any way, just don't forget to give credit :)/>/>
It's very easy to add menu functions, the code has comments to help you know where to add the code.
If you make some modification you can post it here if you want.
Any feedback and suggestions are welcome.
Spoiler
-- GChat - chat program
-- by MysticT
-- Config
local nMinNameLen = 3 -- minimum user name lenght
local nMaxNameLen = 8 -- maximum user name lenght
local nMaxHistory = 50 -- maximum chat history size, set to nil to disable
-- System vars
local nScreenW, nScreenH = term.getSize()
local tUsers = {}
-- User message vars
local sUsrName = ""
local sUsrMsg = ""
local nPos = 0
-- Received messages vars
local tMessages = {}
local nMsg = 1
-- Menu vars
local bMenu = false
local nSelected = 1
local tMenuFunctions = {}
local tMenuOptions = {}
-- Menu functions vars
-- Add any variable you need here
local bExit = false
local function Clear()
term.clear()
term.setCursorPos(1, 1)
end
local function OpenAll()
for _,side in ipairs(rs.getSides()) do
rednet.open(side)
end
end
local function AddMessage(sMsg, sName)
if #sMsg > 0 then
local msg
if sName then
msg = sName..": "..sMsg
else
msg = "<"..sMsg..">"
end
table.insert(tMessages, msg)
if #tMessages - nMsg >= nScreenH - 1 then
nMsg = nMsg + 1
end
if nMaxHistory ~= nil and #tMessages > nMaxHistory then
table.remove(tMessages, 1)
if nMsg > 1 then
nMsg = nMsg - 1
end
end
end
end
local function AddUser(nID, sName)
tUsers[nID] = sName
AddMessage("User "..sName.." connected from "..tostring(nID))
end
local function RemoveUser(nID)
AddMessage("User "..tUsers[nID].." disconnected")
tUsers[nID] = nil
end
local function WriteMsg(sText)
local x, y = term.getCursorPos()
local function newLine()
x = 1
y = y + 1
term.setCursorPos(x, y)
if y < nScreenH - 2 then
return true
end
return false
end
while #sText > 0 do
local whitespace = string.match(sText, "^[ t]+")
if whitespace then
term.write(whitespace)
x, y = term.getCursorPos()
sText = string.sub(sText, #whitespace + 1)
end
local newline = string.match(sText, "^n")
if newline then
if not newLine() then
return true
end
sText = string.sub(sText, 2)
end
local text = string.match(sText, "^[^ tn]+")
if text then
sText = string.sub(sText, #text + 1)
if #text > nScreenW then
while #text > 0 do
if x > nScreenW then
if not newLine() then
return true
end
end
term.write(text)
text = string.sub(text, (nScreenW - x) + 2)
x, y = term.getCursorPos()
end
else
if x + #text > nScreenW then
if not newLine() then
return true
end
end
term.write(text)
x, y = term.getCursorPos()
end
end
end
return false
end
local function WriteMessages()
local i = 0
while nMsg + i <= #tMessages and i < nScreenH - 1 do
if WriteMsg(tMessages[nMsg + i]) then
break
end
local x, y = term.getCursorPos()
term.setCursorPos(1, y + 1)
i = i + 1
end
end
local function RedrawUserMsg()
local nScroll = 0
if nPos + 3 >= nScreenW then
nScroll = nPos + 3 - nScreenW
end
term.setCursorPos(1, nScreenH)
write("> ")
write(string.sub(sUsrMsg, nScroll + 1))
term.setCursorPos(nPos + 3 - nScroll, nScreenH)
end
local function RedrawMenu()
term.setCursorPos(1, nScreenH)
for i, s in ipairs(tMenuOptions) do
if i == nSelected then
term.write("["..s.."]")
else
term.write(s)
end
term.write(" ")
end
end
local function Redraw()
Clear()
WriteMessages()
if bMenu then
RedrawMenu()
else
RedrawUserMsg()
end
end
local function ParseMsg(nID, sMsg)
local sAction, sArgs = string.match(sMsg, "(%a+): (.+)")
if sAction == "MSG" then
AddMessage(sArgs, tUsers[nID])
elseif sAction == "PONG" then
AddUser(nID, sArgs)
elseif sAction == "PING" then
AddUser(nID, sArgs)
rednet.send(nID, "PONG: "..sUsrName)
elseif sAction == "QUIT" then
RemoveUser(nID)
end
end
local function Ping()
rednet.broadcast("PING: "..sUsrName)
end
local function Disconnect()
for id,_ in pairs(tUsers) do
rednet.send(id, "QUIT: "..sUsrName)
end
end
local function SendMsg()
AddMessage(sUsrMsg, sUsrName)
for id,_ in pairs(tUsers) do
rednet.send(id, "MSG: "..sUsrMsg)
end
sUsrMsg = ""
nPos = 0
end
local function DoMenuItem()
tMenuFunctions[nSelected]()
nSelected = 1
end
function KeyPress(key)
if key == 28 then -- Enter
if bMenu then
DoMenuItem()
else
SendMsg()
end
elseif key == 203 then -- Left
if bMenu then
if nSelected > 1 then
nSelected = nSelected - 1
end
else
if nPos > 0 then
nPos = nPos - 1
end
end
elseif key == 205 then -- Right
if bMenu then
if nSelected < #tMenuOptions then
nSelected = nSelected + 1
end
else
if nPos < #sUsrMsg then
nPos = nPos + 1
end
end
elseif key == 14 then -- Backspace
if not bMenu then
if nPos > 0 then
sUsrMsg = string.sub(sUsrMsg, 1, nPos - 1)..string.sub(sUsrMsg, nPos + 1)
nPos = nPos - 1
end
end
elseif key == 211 then -- Delete
if not bMenu then
sUsrMsg = string.sub(sUsrMsg, 1, nPos)..string.sub(sUsrMsg, nPos + 2)
end
elseif key == 199 then -- Start
if bMenu then
nSelected = 1
else
nPos = 0
end
elseif key == 207 then -- End
if bMenu then
nSelected = #tMenuOptions
else
nPos = #sUsrMsg
end
elseif key == 200 then -- Up
if nMsg > 1 then
nMsg = nMsg - 1
end
elseif key == 208 then -- Down
if nMsg < #tMessages then
nMsg = nMsg + 1
end
elseif key == 29 then -- Ctrl
bMenu = not bMenu
term.setCursorBlink(not bMenu)
end
end
local function AddChar(sChar)
sUsrMsg = string.sub(sUsrMsg, 1, nPos)..sChar..string.sub(sUsrMsg, nPos + 1)
nPos = nPos + 1
end
local function CheckUserName()
if #sUsrName < nMinNameLen then
return false, "Name too short."
elseif #sUsrName > nMaxNameLen then
return false, "Name too long."
end
return true
end
-- Menu
-- Add Menu functions here --
--[[
tMenuOptions[n] = "your option name"
tMenuFunctions[n] = function()
-- Your code here
end
--]]
table.insert(tMenuOptions, "Exit")
table.insert(tMenuFunctions, function()
bExit = true
end )
-- Main loop
repeat
Clear()
print("- Welcome to GChat -")
write("Enter your name: ")
sUsrName = read()
local bValid, err = CheckUserName()
if not bValid then
print(err)
sleep(2)
end
until bValid
OpenAll()
Ping()
term.setCursorBlink(true)
while not bExit do
Redraw()
local evt, arg1, arg2 = os.pullEvent()
if evt == "key" then
KeyPress(arg1)
elseif evt == "char" then
AddChar(arg1)
elseif evt == "rednet_message" then
ParseMsg(arg1, arg2)
end
end
Disconnect()
Clear()
Edit: just fixed a little error (calling Ping before connecting)