Bosschat
Spoiler
RecipesIn-game chat too BORING for you? Or maybe playing SSP and you tend to forget things? Well be amazed, another person has written a chat program for you!
Combining the most advanced programming techniques in the world with amazing good looks, code was born. Sporting exactly 2 features, Bosschat stands at 358 lines long. Leave yourself messages from the mines, write down directions to/from that lava pool you fell into, hoping your items are still there, and even ask yourself how your day is going.
Now in intermediate stage (No longer at basic stage).
Features (I guess)
Hold on to your seats, it's about to get real.
Programming is hard, I know that. Lua is different, I know that as well. I never learned Lua in school. My brother and I both weren't even sure this was a real programming language. But now I know it's real enough, anyway. I'm getting back into programming after a 3 year break (when I graduated high school) and this program is really for me, like a test. But at the same time, I'd be willing to help others who have no clue what their doing or are writing really inefficient code. If you feel like you need help programming and you also feel that my ability is sufficient enough to assist you, then by all means send me a PM. I try to respond...
Code (I am just a simple man)
Suggestions (God I love suggestions)
​Please post suggestions in the comments and I will review them and most likely add the most advanced ones. But all suggestions are welcome.
Version History or something
Combining the most advanced programming techniques in the world with amazing good looks, code was born. Sporting exactly 2 features, Bosschat stands at 358 lines long. Leave yourself messages from the mines, write down directions to/from that lava pool you fell into, hoping your items are still there, and even ask yourself how your day is going.
Now in intermediate stage (No longer at basic stage).
Features (I guess)
- Is actually able to send and receive messages from other computers!
- Commands, commands, commands. Bosschat is able to handle commands. There are a few supported commands, /exit or /quit will exit BossChat, /name [username] will change your name from the compID to what you choose (Please Note: This code is so advanced that new usernames will only be in lowercase).
- A GUI more beautiful than finding diamonds that aren't inside/above lava pools.
- Global chatroom (more on this later)
- Backspacing!
- [BUGGED] It even tells you when you have caps lock enabled! (Warning: Pressing 'caps lock' too many times may cause death. Many subjects family members have since removed that key from their home PC's. BossChat Industries will not be held accountable for any damages to persons/objects that occur through repeated use of the 'caps lock' key.)
- Mute and unmute commands. Read the version history for more info.
- Automatic updates
- Tells in-game time
- Saves up to the most 30 recent messages in memory
- As of v.010 no longer shows if caps lock is on.
- If there are no computers already running BossChat, do not check for an update. Causes a program crash.
- If you break a released version of this program without editing it, I will mail you cookies everyday for life. Only applies to unknown bugs.
- Add message encryption (started)
- Private rooms (started)
- More commands (always looking for more)
- Dynamic modem placement (FINISHED. For v.005 - v.010 modem must be on right side)
- Local user database
Hold on to your seats, it's about to get real.
Programming is hard, I know that. Lua is different, I know that as well. I never learned Lua in school. My brother and I both weren't even sure this was a real programming language. But now I know it's real enough, anyway. I'm getting back into programming after a 3 year break (when I graduated high school) and this program is really for me, like a test. But at the same time, I'd be willing to help others who have no clue what their doing or are writing really inefficient code. If you feel like you need help programming and you also feel that my ability is sufficient enough to assist you, then by all means send me a PM. I try to respond...
Code (I am just a simple man)
Spoiler
This code is too advanced to be uploaded to pastebin or any other file-hosting site where it is available for direct download. Plus, I don't know how to do that so it all works out. Must be directly injected into your computer.local tArgs = {...} local cursorY = 17 local username = tostring(os.computerID()) local cMessage = "" local hMessage = "" local charNum = tonumber(1) local message = {"left", "right", "front", "back", "top", "bottom"} local pastCount = 1 local pastMess = {} local capOn = false local room = "global" local muted = false local pVer = "011" local tTimer = os.startTimer(1) local terminate = false local update = false local pMessNum = 30 local modem = 0 if #tArgs < 1 or #tArgs > 2 then print("Usage: bosschat <modem_side> <username(op)>") terminate = true end if tArgs[1] ~= nil and tArgs[1] ~= "debug" then for i = 1, 6 do if tArgs[1] == message[i] then rednet.open(message[i]) print("Opening modem on " .. tArgs[1]) else modem = modem + 1 end end if modem == 6 then print("Modem not found on " .. tArgs[1]) print("Program will close.") terminate = true end end if tArgs[2] ~= nil then username = string.upper(string.sub(tArgs[2], 1, 1)) .. string.lower(string.sub(tArgs[2], 2)) end for i = 1, 48 - (string.len(username) + 2) do --These two loops initialize message[] which is what you type and pastMess[i] which is a combination of messages you have received/sent. message[i] = "" end for i = 1, pMessNum do pastMess[i] = "" end function verCheck() rednet.broadcast("UTIL v." .. pVer) print("Detecting local clients.") local id, message = rednet.receive(2) if message == nil then print("NOTE: No other users!") sleep(3) elseif tonumber(string.sub(message, 8)) > tonumber(pVer) then print("Client found!") print("Update required!") sleep(3) rednet.broadcast("UTIL READY") if tonumber(pVer) < 10 then pVer = "00" .. tonumber(pVer) elseif tonumber(pVer) < 100 then pVer = "0" .. tonumber(pVer) end print("Updating BossChat v." .. pVer .. " to v." .. string.sub(message,8)) shell.run("updater") terminate = true else print("Client found!") print("Client up-to-date!") sleep(3) --version = fs.open("version", "r") --if version then --local vID = version.readLine() --version.close() --end --if tonumber(vID) >= tonumber(pVer) then --ASK FOR UPDATE --else end end function cUpdater() updater = fs.open("updater", "w") if updater then updater.writeLine([[rednet.open("right")]]) updater.writeLine([[rednet.broadcast("UPDATE")]]) updater.writeLine([[event, id, message = os.pullEvent("rednet_message")]]) updater.writeLine("") updater.writeLine([[update = fs.open("bosschat", "w")]]) updater.writeLine("if update then") updater.writeLine(" update.writeLine(message)") updater.writeLine(" update.close()") updater.writeLine("end") updater.close() end end function clearScreen() term.clear() term.setCursorPos(1,1) end function resetMessage() --Clears message[], same thing as inizialization. Called when pressing "enter". for i = 1, 48 - (string.len(username) + 2) do message[i] = "" end charNum = 1 end function Time() --Tells current Minecraft time in the corner, bugged Caps Lock "feature" term.setCursorPos(45,2) if math.floor(os.time()) <= 9 then term.write(" ") end term.write(textutils.formatTime(os.time(), true)) tTimer = os.startTimer(1) end function updatePast(newMess) --Updates the array pastMess[] and then calls updateScreen(). Might turn those two into a single function. for i = 1, pMessNum - 1 do pastMess[i] = pastMess[i + 1] end pastMess[pMessNum] = newMess updateScreen() end function updateScreen() --Updates the screen with new messages. if muted == false then for i = 4, 15 do term.setCursorPos(1, i) term.clearLine() end for i = 4, 15 do term.setCursorPos(1, i) term.write("|") term.setCursorPos(50, i) term.write("|") end local counter = 0 for i = 12, 1, -1 do term.setCursorPos(2, i + 3) term.write(pastMess[pMessNum - counter]) counter = counter + 1 end end end function Border() --Creates the space clearScreen() for i = 1, 50 do term.setCursorPos(i, 1) term.write("-") term.setCursorPos(i, 3) term.write("-") term.setCursorPos(i, 16) term.write("-") term.setCursorPos(i, 18) term.write("-") end for i = 1, 18 do term.setCursorPos(1, i) term.write("|") term.setCursorPos(50, i) term.write("|") end term.setCursorPos(2, 2) term.write("BossChat v." .. pVer) --handled with version checking end function handleBackspace() if charNum + 1 >= 3 then charNum = charNum - 1 message[charNum] = " " term.setCursorPos(charNum + string.len(username) + 3, cursorY) term.write(" ") term.setCursorPos(charNum + string.len(username) + 3, cursorY) elseif charNum <= 1 then charNum = 1 end end function handleSend(message) --Reads message[] letter by letter, saves it, clears the line and recreates the space. Then updates past messages and finally sends it. for i = 1, charNum do hMessage = hMessage .. message[i] end term.setCursorPos(1, 17) term.clearLine() term.setCursorPos(1, 17) term.write("|") term.setCursorPos(50, 17) term.write("|") if string.find(hMessage, "/") == 1 then handleCommand(hMessage) elseif hMessage ~= "" then updatePast("[" .. username .. "]" ..hMessage) messageSend(username, hMessage) end resetMessage() return hMessage end function handleCaps(capOn) --Currently bugged if capOn == false then term.setCursorPos(20, 2) term.write("CAPS ON") capOn = true elseif capOn == true then term.setCursorPos(20, 2) term.write(" ") capOn = false end end function handleCommand(command) --Handles all commands, easy to add new commands. command = string.upper(command) if string.sub(command, 1, 5) == "/EXIT" or string.sub(command, 1, 5) == "/QUIT" then term.setCursorPos(2, 17) term.write("Thank you for using BossChat") for i = 1, 5 do term.write(".") sleep(0.0) --Took out exit delay end hMessage = "" terminate = true elseif string.sub(command, 1, 5) == "/NAME" then hMessage = string.upper(string.sub(command, 7, 7)) .. string.lower(string.sub(command, 8)) updatePast("Name changed to " .. hMessage .. ".") username = hMessage elseif string.sub(command, 1, 5) == "/ROOM" then room = string.sub(command, 7) updatePast("Now speaking in " .. room .. ".") elseif string.sub(command, 1, 5) == "/MUTE" then updatePast("You have muted the room.") muted = true elseif string.sub(command, 1, 7) == "/UNMUTE" then muted = false updatePast("You have unmuted the room.") elseif string.sub(command, 1, 6) == "/CLEAR" then for i = 1, 12 do pastMess[i] = "" end updateScreen() else updatePast(string.sub(command, 1, charNum) .. " currently does not exist.") end end function writeChar(char) --Writes each character letter by letter and saves it in message[]. term.setCursorPos(charNum + string.len(username) + 3, cursorY) if charNum <= 48 - (string.len(username) + 2) then term.write(char) message[charNum] = char charNum = charNum + 1 end end function handleKey(key) --Handles misc. keys. if key == 58 then --handleCaps(capOn) --Bugged after using timers. Remove comments if you think you can make it work and send me edits to put in final version. elseif key == 14 then handleBackspace() elseif key == 28 then pMessNum = 30 hMessage = handleSend(message) hMessage = "" term.setCursorPos(2, 17) term.write("[" .. username .. "]") elseif key == 200 and pastMess[pMessNum - 1] ~= "" then --Moves messages up once, second check prevents moving higher than an empty message. if pMessNum >= 13 then pMessNum = pMessNum - 1 updateScreen(pMessNum) end elseif key == 208 then --Moves messages down once if pMessNum <= 29 then pMessNum = pMessNum + 1 updateScreen(pMessNum) end end end function handleTimers(timer) --Handles timers, currently only timer that updates clock exists. if timer == tTimer then Time() end end function handleUtilities(id, message) if string.sub(message, 6, 7) == "v." then rednet.broadcast("UTIL v." .. pVer) elseif string.sub(message, 6) == "READY" then bosschat = fs.open("bosschat", "r") if bosschat then local update = bosschat.readAll() bosschat.close() rednet.send(id, update) end end end function messageReceive(id, message) --Lots of work needs to be done here... if string.sub(message, 1, 4) == "UTIL" then handleUtilities(id, message) else pMessNum = 30 updatePast(message) end end function messageSend(username, hMessage) --LOADS of work needs to be done here. rednet.broadcast(string.len(username) .. "e" .. "[" .. username .. "]" .. string.len(room) .. "e " .. room .. " " .. hMessage) end function handleEvent() --The main function that makes it all happen. evt, p1, p2 = os.pullEvent() if evt == "char" then writeChar(p1) elseif evt == "key" then handleKey(p1) elseif evt == "rednet_message" then messageReceive(p1, p2) elseif evt == "timer" then handleTimers(p1) end end if terminate == false then clearScreen() --"Beginning" of program. (Visual stuff begins to happen here) if tArgs[1] ~= "debug" then cUpdater() verCheck() end if terminate == true then print("BossChat has been updated! Please restart the program.") print("Press enter to continue") io.read() end Border() term.setCursorPos(2, 17) term.write("[" .. username .. "]") term.setCursorPos(2, 17) updatePast("Speaking in " .. room .. ".") Time() end while terminate == false do handleEvent() end if #tArgs > 0 and modem ~= 6 then clearScreen() print("CraftOS 1.3") end
Suggestions (God I love suggestions)
​Please post suggestions in the comments and I will review them and most likely add the most advanced ones. But all suggestions are welcome.
Version History or something
- 6/13 v.011 Small-ish update. Haven't updated in a while so I figured I would. Major bug from last update fixed. Added true automatic updates. Program can accept parameters. Usage: bosschat <modem_side> <username (optional)>. Type 'debug' in place of a modem Small fix when scrolling upwards through past messages (program would scroll upwards through empty messages). Added /quit which does exactly the same as /exit because it uses the same code. Exiting BossChat no longer restarts your computer, just ends the program and simulates the screen as if it had been.
- 6/05 Major update released. Changes in spoiler:
Spoiler
Okay, not exactly an auto-updater (due to problems with extremely advanced code), but an updater has been released. To update, simply run BossChat on a computer with a lower Version Identifier (or something) and enter 'Y' or 'y' when prompted. Should always update okay. Make sure your modems are on the right side. NOTE: Only for clients v.010 and later. ALSO NOTE: This version is BUGGED. If there are no other clients and you attempt to update, it will timeout and return with an error. SO DON'T DO THAT (type 'n' and hit enter). I think I found a way around this, but I'm done coding for tonight. If anybody reads this far down and knows how to check for a string being equal to nil, please tell.
FOR A COMPUTER WITHOUT BOSSCHAT: You need to have the updater. Here it is. Highly versatile, can be used to transfer other files with a pinch of editing. Make sure you change "bosschat" to something else if you decide to edit. Don't want to overwrite it.
Just run this program after BossChat is running on the computer you want to update FROM.
Programming advances have allowed the addition of a clock.
Now with time travel! Bosschat now saves up to 30 messages (including Command printouts). Press the up arrow to scroll back in time and down arrow to return to the present! If you send or receive a message while looking at past messages, BossChat will automatically scroll to the bottom. This is considered a feature, but it is understandable how this could get annoying. Can be easily edited to save more messages due to advanced programming techniques.
Left debug data for private rooms in sent messages. You'll see what I mean when you run. Adding those headers will help when I inevitably finish this project and work on networking so this can all come together on a giant server (that someone else will host (my computer is ass)).
Bunch of small stuff that no one will notice/care about.
Okay, not exactly an auto-updater (due to problems with extremely advanced code), but an updater has been released. To update, simply run BossChat on a computer with a lower Version Identifier (or something) and enter 'Y' or 'y' when prompted. Should always update okay. Make sure your modems are on the right side. NOTE: Only for clients v.010 and later. ALSO NOTE: This version is BUGGED. If there are no other clients and you attempt to update, it will timeout and return with an error. SO DON'T DO THAT (type 'n' and hit enter). I think I found a way around this, but I'm done coding for tonight. If anybody reads this far down and knows how to check for a string being equal to nil, please tell.
FOR A COMPUTER WITHOUT BOSSCHAT: You need to have the updater. Here it is. Highly versatile, can be used to transfer other files with a pinch of editing. Make sure you change "bosschat" to something else if you decide to edit. Don't want to overwrite it.
Spoiler
rednet.open("right") rednet.broadcast("READY") event, id, message = os.pullEvent("rednet_message") update = fs.open("bosschat", "w") if update then update.writeLine(message) update.close() end
Just run this program after BossChat is running on the computer you want to update FROM.
Programming advances have allowed the addition of a clock.
Now with time travel! Bosschat now saves up to 30 messages (including Command printouts). Press the up arrow to scroll back in time and down arrow to return to the present! If you send or receive a message while looking at past messages, BossChat will automatically scroll to the bottom. This is considered a feature, but it is understandable how this could get annoying. Can be easily edited to save more messages due to advanced programming techniques.
Left debug data for private rooms in sent messages. You'll see what I mean when you run. Adding those headers will help when I inevitably finish this project and work on networking so this can all come together on a giant server (that someone else will host (my computer is ass)).
Bunch of small stuff that no one will notice/care about.
- 5/31 Major unreleased update to code.
- 5/30 Added '/mute' and '/unmute' commands. Mute will keep your computer from updating the screen, although the messages will still be saved. Unmute will allow your computer to start updating the screen again and will display as many messages as possible that you missed (There is currently a maximum of 12 saved messages, and subtract one. Thank Teraminer for the idea.
- 5/29 First official release BossChat v.005. Came up with name BossChat on the fly.
- Pre-5/29 Rewrote code twice, making it more advanced each time. Used third rewrite as the base for BossChat v.005
Spoiler
Special thanks to Max96at!
https://dl.dropbox.c...cs/bawsChat.png
Special thanks to thesbros for all of these!
https://dl.dropbox.c...bosschat-3d.png
https://dl.dropbox.c...schat-gears.png
https://dl.dropbox.c...at-gradient.png
https://dl.dropbox.c...schat-rocky.png
https://dl.dropbox.c...bosschat-mc.png
https://dl.dropbox.c...osschat-idk.png
https://dl.dropbox.c...cs/bawsChat.png
Special thanks to thesbros for all of these!
https://dl.dropbox.c...bosschat-3d.png
https://dl.dropbox.c...schat-gears.png
https://dl.dropbox.c...at-gradient.png
https://dl.dropbox.c...schat-rocky.png
https://dl.dropbox.c...bosschat-mc.png
https://dl.dropbox.c...osschat-idk.png
Spoiler
Here's a bit of code I was working on, the reason I took a break from BossChat for a few days was to get familiar with having programs accept arguments during run-time. Result can be seen in the 6/13 update for BossChat, anyway here's the code for a program that will tell you how many of each item you can create with certain materials. Type 'recipe' for arguments used and type 'recipe <item>' to see which arguments are accepted. I'm fed up with this code, will not be updating it, and anyone that is willing to try to use it is welcome to as long as they write that they got the base from me.
Working items:
Working items:
- Dispensers
- Noteblocks
- Powered Rails (untested)
- Detector Rails (untested, unfinished and buggy)
- Signs
- Everything not listed above
Spoiler
local tArgs = { ... } local rItem = {" ", " ", " ", " ", " ", " ", " ", " ", " "} local create = 0 local cItem = 0 local rec = "" term.clear() term.setCursorPos(1,1) if #tArgs < 1 then print("Usage: recipe <item> <material 1> <mat 2> etc") print("Usage: recipe reverse <amount> <item>") return end function craft(rItem) print(" - - -") print("|" .. rItem[1] .. "|" .. rItem[2] .. "|" .. rItem[3] .. "|") print(" - - -") print("|" .. rItem[4] .. "|" .. rItem[5] .. "|" .. rItem[6] .. "|") print(" - - -") print("|" .. rItem[7] .. "|" .. rItem[8] .. "|" .. rItem[9] .. "|") print(" - - -") end local item = tArgs[1] if item == "dispenser" then if #tArgs ~= 4 then print("Usage: recipe dispenser <bow> <cobblestone> <redstone>") else bow = tArgs[2] cobblestone = tArgs[3] redstone = tArgs[4] while tonumber(bow) > 0 and tonumber(cobblestone) > 6 and tonumber(redstone) > 0 do --Remove tonumber() to see why I am finished with this code. bow = bow - 1 cobblestone = cobblestone - 7 redstone = redstone - 1 cItem = cItem + 1 end print("Dispensers: " .. cItem) if bow == 0 and cobblestone == 0 and redstone == 0 then else print("") print("Materials left:") print("Bows: " .. bow) print("Cobblestone: " .. cobblestone) print("Redstone: " .. redstone) end print("Need recipe? (Y/N)") rec = io.read() if string.upper(rec) == "Y" then for i = 1, 9 do if i ~= 5 or i ~= 8 then rItem[i] = "c" end end rItem[5] = "b" rItem[8] = "r" craft(rItem) print("c = cobblestone") print("b = bow") print("r = redstone") end end elseif item == "noteblock" then if #tArgs ~= 2 then print("Usage: recipe noteblock <wood> <plank> <redstone>") else plank = tArgs[3] + (tArgs[2] * 4) redstone = tArgs[4] while plank > 7 and redstone > 0 do plank = plank - 8 redstone = redstone - 1 cItem = cItem + 1 end print("Noteblocks: " .. cItem) if plank == 0 and redstone == 0 then else print("Planks: " .. plank) print("Redstone: " .. redstone) end print("Need recipe? (Y/N)") rec = io.read() if string.upper(rec) == "Y" then for i = 1, 9 do if i ~= 5 then rItem[i] = "p" end end rItem[5] = "r" craft(rItem) print("p = plank") print("r = redstone") end end elseif item == "powered_rail" then if #tArgs ~= 6 then print("Usage: recipe sign <wood> <plank> <stick> <gold> <redstone>") else plank = tArgs[3] + (tArgs[2] * 4) stick = tArgs[4] gold = tArgs[5] redstone = tArgs[6] while stick > 0 and redstone > 0 and gold > 5 do if stick < 2 and plank > 1 then plank = plank - 2 stick = stick + 4 create = create + 1 end gold = gold - 6 stick = stick - 1 redstone = redstone - 1 cItem = cItem + 1 end print("Powered Rails: " .. cItem) if create ~= 0 then print("") print("You will need to create: " .. create *4 .. " sticks.") end if gold == 0 and redstone == 0 and stick == 0 then else print("Gold: " .. gold) print("Redstone: " .. redstone) print("Stick: " .. stick) end print("Need recipe? (Y/N)") rec = io.read() if string.upper(rec) == "Y" then for i = 1, 9 do if i ~= 2 and i ~= 5 and i ~= 8 then rItem[i] = "g" end end rItem[5] = "s" rItem[8] = "r" craft(rItem) print("g = gold") print("r = redstone") print("s = stick") end end elseif item == "detector_rail" then if #tArgs ~= 4 and #tArgs ~= 5 then print("Usage: recipe detector_rail <iron> <redstone> <pressure_plate>") print("Optional usage: recipe etc. <pressure_plate> <cobblestone>") else iron = tArgs[2] redstone = tArgs[3] pressplate = tArgs[4] cobblestone = tArgs[5] if pressplate == 0 and cobblestone >= 4 then cobblestone = cobblestone - 4 pressplate = pressplate + 2 create = create + 2 end while tonumber(iron) > 5 and tonumber(redstone) > 0 and tonumber(pressplate) > 0 do --remove tonumber() to see dysfunctional code in action. if tonumber(pressplate) < 2 and tonumber(tArgs[5]) ~= nil and tonumber(cobblestone) > 1 then --remove tonumber() to see why every table in my house has been flipped. cobblestone = cobblestone - 2 pressplate = pressplate + 1 create = create + 1 end iron = iron - 6 redstone = redstone - 1 pressplate = pressplate - 1 cItem = cItem + 1 end print("Detector Rails: " .. cItem) if create ~= 0 then print("") print("You will need to create: " .. create .. " pressure plates.") end if iron == 0 and redstone == 0 and pressplate == 0 then else print("Iron: " .. iron) print("Redstone: " .. redstone) print("Pressure Plates: " .. pressplate) end end elseif item == "sign" then if #tArgs ~= 4 then print("Usage: recipe sign <wood> <plank> <stick>") else plank = tArgs[3] + (tArgs[2] * 4) stick = tArgs[4] print("Calculating") while tonumber(plank) >= 6 do if stick == 0 and plank > 7 then plank = plank - 2 stick = stick + 4 create = create + 1 end plank = plank - 6 stick = stick - 1 cItem = cItem + 1 end print("Signs: " .. cItem) if create ~= 0 then print("") print("You will need to create: " .. create * 4 .. " sticks.") end if plank == 0 and stick == 0 then else print("") print("Materials left:") print("Planks: " .. plank) print("Sticks: " .. stick) end end end
Edited by Bossman201, 03 July 2012 - 02:34 AM.