View difference between Paste ID: k2580jZ5 and JtgbWdV5
SHOW: | | - or go back to the newest paste.
1
--[[
2
 pastebin get JtgbWdV5 enchat 
3
 std pb JtgbWdV5 enchat 
4
 std ld enchat enchat 
5
6-
'Enchat' version 2.3 by EldidiStroyrr (CC Forums: LDDestroier)
6+
'Encmail' version 0.1 by EldidiStroyrr (CC Forums: LDDestroier)
7
8-
Encrypted, decentralized, colorized modem chat program for ComputerCraft 1.6 or later.
8+
Encrypted, decentralized, colorized EMAIL program for ComputerCraft 1.6 or later.
9
Encrypts messages/usernames with a password and os.time()
10-
Color your text with &[color code] and ~[color code], with &k obfuscation.
10+
Color your text with &[color code] and ~[color code].
11
Disable text formatting with &{, and re-enable it with &}.
12-
If you connect Enchat to Plethora's terminal glasses, you'll get notifications.
12+
Use &k to obfuscate, and ~k to stop obfuscation. Hehe.
13
This program is based on Enchat, and is incomplete.
14-
Forum link:
14+
15
Forum link for Enchat:
16
http://www.computercraft.info/forums2/index.php?/topic/25290-enchat-encrypted-decentralized-chat/
17-
This is a stable release. You fool!
17+
18
This is a beta release. You fool!
19
20
Working on:
21
 +making an interface like a standard email program
22
 +making an address book
23-
local encKey, yourName = tArg[1] or (_USERNAME and tostring((os.getComputerID() + math.pi) * math.pi) or nil), tArg[2] or _USERNAME
23+
 +getting a solid folder hierarchy
24
 +removing all unneccesary fucking garbage text goddamn it
25-
log = {}								--Log formatted for view.
25+
26-
_log = {}								--Log with all information.
26+
27-
chatlog = {}							--Log with all preformatted information.
27+
28-
local commandTable						--Contains all commands.
28+
local em_path = ".encmail"
29-
local scr_x, scr_y = term.getSize()		--I hate all who use hard coded screen sizes.
29+
local logpath = fs.combine(em_path,"logs")
30-
local fixedChannel = nil				--Specify modem channel if you need to.
30+
local configpath = fs.combine(em_path,"config")
31-
local checksum, modems, scroll, doScroll, channel
31+
32
local displayMode = "mainmenu"
33
34
local timedivisor = 2 --Must be same as other enchat clients. Can be used to limit scrambling due to using os.time
35-
local isBeta = false --Affects the /update command and some text.
35+
36
local tArg = {...}
37-
local enchatVersion = "2.3" --String, not number!
37+
local encKey, yourName = tArg[1], tArg[2]
38
39-
_G.enchat_name_history = _G.enchat_name_history or {}
39+
log = {}	     --Log formatted for view
40
_log = {}	     --Log with all information
41
chatlog = {}   --Log with all pre-formatted information
42
local commandTable   --Contains all commands
43
local scr_x, scr_y = term.getSize()
44
local channel = 0 --Do not modify, it's changed anyway
45-
	krazyDrawDelay = 0.2, --Delay in seconds between redrawing obfuscated text.
45+
local checksum, modems, scroll, doScroll
46-
	emulateModem = false, --Skips modem check, and allows use in CCEmuRedux (all computers have distance of 0...)
46+
47-
	useSetVisible = true, --Whether or not to use term.current().setVisible() when possible to reduce flickering
47+
48-
	pageKeySpeed = 4, --Amount of lines scrolled when using pageUp or pageDown.
48+
49-
	doKrazy = true, --Determines if you want the screen to update every time there's obfuscated text. Causes major flickering.
49+
50-
	doNotif = true, --If terminal glasses are present, will push all messages to the screen.
50+
51
	fancyMsg = true, --Whether or not to colorize as you type
52-
if string.find(_HOST or "","CCEmuRedux") then enchatSettings.emulateModem = true end
52+
53
	reverseScroll = false, --Reverses scrolling direction. But why would you want to do that?
54
}
55
56
local palate = {
57
	bg = colors.gray, --Default chat background color
58
	txt = colors.white, --Default chat text color
59
	chatbg = colors.white, --Chat prompt background color
60
	chattxt = colors.black, --Chat prompt text color
61-
pburls = {
61+
62-
	beta = "https://pastebin.com/raw/4a6NZaMZ",
62+
63-
	stable = "https://pastebin.com/raw/JtgbWdV5",
63+
64
	["0"] = colors.white,
65
	["1"] = colors.orange,
66
	["2"] = colors.magenta,
67
	["3"] = colors.lightBlue,
68
	["4"] = colors.yellow,
69
	["5"] = colors.lime,
70
	["6"] = colors.pink,
71
	["7"] = colors.gray,
72
	["8"] = colors.lightGray,
73
	["9"] = colors.cyan,
74
	["a"] = colors.purple,
75
	["b"] = colors.blue,
76
	["c"] = colors.brown,
77
	["d"] = colors.green,
78
	["e"] = colors.red,
79
	["f"] = colors.black,
80
}  
81
82
--going to add compatibility for ComputerCaft 1.63
83
local _currentcolors = {
84
	txt = colors.white,
85
	bg = colors.black,
86-
if term.isColor() then --this is a useful check, albeit a hardly used check
86+
87
local termsetTextColor,termsetBackgroundColor = term.setTextColor,term.setBackgroundColor
88
local termsetCursorPos,termclear,termclearLine,termwrite,termgetSize,termsetCursorBlink,termisColor = term.setCursorPos,term.clear,term.clearLine,term.write,term.getSize,term.setCursorBlink,term.isColor
89
local tableinsert,tableconcat,tableunpack = table.insert,table.concat,table.unpack
90
local termblit,termgetTextColor,termgetBackgroundColor,termgetCursorPos
91
local parallelwaitForAny = parallel.waitForAny
92
local termsetVisible
93
if term.current then
94
	termcurrent = term.current
95
end
96
97
local oldsettext = term.setTextColor
98-
local ncs = function(col) --No Colors Safe, adjusts colors so that 1.6 normal computers can use Enchat right
98+
99-
	if grayAllowed then
99+
100-
		return col
100+
101
		oldsettext(col)
102-
		if col == colors.gray then
102+
103-
			return colors.black
103+
104-
		elseif col == colors.lightGray then
104+
105-
			return colors.white
105+
106
		_currentcolors.bg = col
107-
			return col
107+
108
	termgetTextColor = function()
109
		return _currentcolors.txt
110
	end
111
	termgetBackgroundColor = function()
112
		return _currentcolors.bg
113
	end
114
	termblit = function(txt,tx,bg)
115
		local pt,pb = _currentcolors.bg,_currentcolors.txt
116
		if type(txt) ~= "string" or type(tx) ~= "string" or type(bg) ~= "string" then
117
			error("expected 3 strings, got "..tableconcat({type(txt),type(tx),type(bg)},", "))
118
		end
119
		if not ((#txt == #tx) and #tx == #bg) then
120
			error("all three arguments must be of same length")
121
		end
122
		for p = 1, #txt do
123
			oldsettext(colors_names[tx:sub(p,p)])
124
			oldsetbg(colors_names[bg:sub(p,p)])
125
			termwrite(txt:sub(p,p))
126
		end
127
		oldsettext(pt)
128
		oldsettext(pb)
129
	end
130
else
131
	termblit = term.blit
132
	termgetTextColor = term.getTextColor
133
	termgetBackgroundColor = term.getBackgroundColor
134
	termgetCursorPos = term.getCursorPos
135
end
136
137
local tableConcat = function(tbl,between)
138
	local output = ""
139
	for k,v in pairs(tbl) do
140
		output = output..k..between
141
	end
142
	return output:sub(1,-2)
143
end
144
145
--Loading AES encryption functions. AES API ported to CC by SquidDev. Thanks heaps!
146
local apipath
147
if shell then apipath = fs.combine(shell.dir(),"aes") else apipath = "" end
148
if (not aes) and (not fs.exists(apipath)) then
149
	print("AES API not found! Downloading...")
150
	local prog = http.get("http://pastebin.com/raw/9E5UHiqv")
151
	if not prog then error("FAIL!") end
152
	local file = fs.open(apipath,"w")
153
	file.write(prog.readAll())
154
	file.close()
155
end
156
if not aes then
157
	local res = os.loadAPI(apipath)
158
	if not res then error("Didn't load AES API!") end
159
end
160
161
--In case I use an API that uses a different syntax than (msg, key)
162
local encrite = function(msg, key)
163
	return aes.encrypt(key, msg)
164
end
165-
local _pairs = pairs
165+
166-
local pairs = function(tbl)
166+
167-
	if not type(tbl) == "table" then
167+
168-
		error("table expected, but I got "..type(tbl))
168+
169
170-
		return _pairs(tbl)
170+
171
	if type(txt) ~= "string" then return false, "requires string" end
172
	return {txt:byte(1,-1)}
173
end
174
175
local decode = function(tbl) --converts an encoded string into something useful.
176
	if type(tbl) ~= "table" then return false, "requires table" end
177-
		output = output..k..(between or "")
177+
178
end
179
180
local strcapsule = function(txt)
181
	return "\""..tostring(txt).."\""
182-
if (tArg[1] or ""):lower() == "update" then
182+
183-
	local url
183+
184-
	if tArg[2] then
184+
185-
		if pburls[tArg[2]:gsub("%s","")] then
185+
186-
			url = pburls[tArg[2]:gsub("%s","")]
186+
187
	termsetCursorPos((scr_x/2)-(#txt/2),setY or y)
188-
			error("No such update link.")
188+
189
	write(txt)
190
end
191-
		url = isBeta and pburls.beta or pburls.stable
191+
192
local waitForModem = function()
193
	local mod
194-
		cfile = shell.getRunningProgram()
194+
195
		sleep(0.2)
196-
		print("Download where?")
196+
197-
		write(":")
197+
198-
		cfile = read()
198+
199
		end
200-
	if fs.isReadOnly(cfile) then
200+
201-
		error("Unable to download to read-only directory.")
201+
202
203-
	if not http then
203+
if not peripheral.find("modem") then
204-
		error("HTTP is disabled. Ask an admin to re-enable it.")
204+
	termsetBackgroundColor(colors.gray)
205
	termsetTextColor(colors.white)
206-
		if not http.checkURL(url) then
206+
207-
			error("Pastebin is...blocked?")
207+
	cwrite("Enchat requires a modem.",3)
208
	cwrite("Add one, or press a key.",4)
209
	sleep(0.1)
210-
	write("Downloading...")
210+
	local outcome = parallelwaitForAny(function() os.pullEvent("key") end, waitForModem)
211-
	local data = http.get(url)
211+
212-
	if not data then
212+
	if #modems == 0 then
213-
		return print("fail")
213+
		termsetBackgroundColor(colors.black)
214
		termsetCursorPos(1,scr_y)
215-
		local file = fs.open(cfile,"w")
215+
216-
		file.write(data.readAll())
216+
		sleep(0)
217-
		file.close()
217+
218-
		print("Success!")
218+
219-
		return
219+
220
221
local modemOpen = function(chan)
222
	for a = 1, #modems do
223
		modems[a].open(chan)
224
	end
225
end
226
227
local modemClose = function(chan)
228
	for a = 1, #modems do
229
		modems[a].close(chan)
230
	end
231
end
232
233
local modemTransmit = function(chan,repchan,msg)
234
	for a = 1, #modems do
235
		modems[a].transmit(chan,repchan,msg)
236
	end
237
end
238
239
local tsv = function(visible)
240
	if termcurrent then
241-
	assert(type(msg) == "string", "message must be string")
241+
		if termcurrent().setVisible then
242-
	assert(type(key) == "string", "key must be string")
242+
243
			return true
244
		else
245
			return false
246
		end
247-
	assert(type(msg) == "string", "message must be string")
247+
248-
	assert(type(key) == "string", "key must be string")
248+
249
	end
250
end
251
252
local logadd = function(name,msg,newline,stopFormatting)
253
	chatlog[#chatlog+1] = {name,msg,newline,stopFormatting or false}
254
end
255
256
local deepCopy = function(tbl)
257
	local output = {}
258
	for k,v in pairs(tbl) do
259
		output[k] = v
260
	end
261
	return output
262
end
263-
	return table.concat({"\"",tostring(txt),"\""})
263+
264
local explode = function(div,str)
265
    if (div=='') then return false end
266
    local pos,arr = 0,{}
267
    for st,sp in function() return string.find(str,div,pos,false) end do
268
        tableinsert(arr,string.sub(str,pos,st-1))
269
        pos = sp + 1
270
    end
271
    tableinsert(arr,string.sub(str,pos))
272
    return arr
273
end
274
275
local colors_strnames = { --primarily for use when coloring palate
276
	["white"] = colors.white,
277
	["orange"] = colors.orange,
278
	["magenta"] = colors.magenta,
279
	["lightpurple"] = colors.magenta,
280
	["light purple"] = colors.magenta,
281
	["lightblue"] = colors.lightBlue,
282
	["light blue"] = colors.lightBlue,
283
	["yellow"] = colors.yellow,
284
	["piss"] = colors.yellow,
285-
local explode = function(div,str,replstr,includeDiv)
285+
286
	["lime"] = colors.lime,
287
	["lightgreen"] = colors.lime,
288
	["light green"] = colors.lime,
289-
        tableinsert(arr,string.sub(replstr or str,pos,st-1+(includeDiv and #div or 0)))
289+
290
	["lightish red"] = colors.pink,
291
	["gray"] = colors.gray,
292-
    tableinsert(arr,string.sub(replstr or str,pos))
292+
293
	["lightgray"] = colors.lightGray,
294
	["lightgrey"] = colors.lightGray,
295
	["light gray"] = colors.lightGray,
296-
local getWord = function(str, pos)
296+
297-
	local words = explode(" ",str)
297+
298-
	local x, exs, ex1, ex2 = 0, "", 0, 0
298+
299-
	for w = 1, #words do
299+
300-
		ex1, ex2 = words[w]:find(". ")
300+
301-
		exs = str:sub(ex1 or 0, ex2 or 0)
301+
302-
		words[w] = (exs or "")..words[w]
302+
303-
		for c = 1, #words[w] do
303+
304-
			x = x + 1
304+
305-
			if x == pos then
305+
306-
				return words[w], w
306+
307
	["red"] = colors.red,
308
	["blood"] = colors.red,
309
	["black"] = colors.black,
310-
		x = (_ox or (x+1)) - 1
310+
311
312-
	return "", -1
312+
313
	colors_strnames[k] = v
314-
local notif = {}
314+
315-
notif.alpha = 248
315+
316-
notif.height = 10
316+
local function alterXY()
317-
notif.width = 6
317+
	local cx,cy = termgetCursorPos()
318-
notif.time = 10
318+
	if cx == scr_x then
319-
notif.wrapX = 300
319+
		termsetCursorPos(1,cy+1)
320-
local nList = {}
320+
321-
local colorTranslate = {
321+
322-
	[" "] = {240, 240, 240},
322+
323-
	["0"] = {240, 240, 240},
323+
324-
	["1"] = {242, 178, 51 },
324+
325-
	["2"] = {229, 127, 216},
325+
326-
	["3"] = {153, 178, 242},
326+
327-
	["4"] = {222, 222, 108},
327+
328-
	["5"] = {127, 204, 25 },
328+
329-
	["6"] = {242, 178, 204},
329+
330-
	["7"] = {76,  76,  76 },
330+
331-
	["8"] = {153, 153, 153},
331+
332-
	["9"] = {76,  153, 178},
332+
333-
	["a"] = {178, 102, 229},
333+
334-
	["b"] = {51,  102, 204},
334+
335-
	["c"] = {127, 102, 76 },
335+
			if not termisColor() then
336-
	["d"] = {87,  166, 78 },
336+
				if (col ~= colors.white) and (col ~= colors.lightGray) and (col ~= colors.gray) and (col ~= colors.black) then
337-
	["e"] = {204, 76,  76 },
337+
					return false
338-
	["f"] = {25,  25,  25 }
338+
339
			end
340-
local interface, canvas = peripheral.find("neuralInterface")
340+
341-
if interface then
341+
342-
	if interface.canvas then
342+
343-
		canvas = interface.canvas()
343+
344-
		notif.newNotification = function(char, text, back, time)
344+
345-
			nList[#nList+1] = {char,text,back,time,1} --last one is alpha multiplier
345+
346
	local wordNo = 1
347-
		notif.displayNotifications = function(doCountDown)
347+
348-
			local adjList = {
348+
349-
				["i"] = -4,
349+
350-
				["l"] = -3,
350+
351-
				["I"] = -1,
351+
352-
				["t"] = -2,
352+
353-
				["k"] = -1,
353+
354-
				["!"] = -4,
354+
355-
				["|"] = -4,
355+
356-
				["."] = -4,
356+
357-
				[","] = -4,
357+
358-
				[":"] = -4,
358+
359-
				[";"] = -4,
359+
360-
				["f"] = -1,
360+
361-
				["'"] = -3,
361+
362-
				["\""] = -1,
362+
363-
				["<"] = -1,
363+
364-
				[">"] = -1,
364+
365
		elseif not (cx == 1 and text:sub(a,a) == " ") then
366-
			local drawEdgeLine = function(y,alpha)
366+
367-
				local l = canvas.addRectangle(notif.wrapX, 1+(y-1)*notif.height, 1, notif.height)
367+
368-
				l.setColor(table.unpack(colorTranslate["0"]))
368+
369-
				l.setAlpha(alpha)
369+
370
					termblit(text:sub(a,a),txt:sub(a,a),bg:sub(a,a))
371-
			local getWordWidth = function(str)
371+
372-
				local output = 0
372+
373-
				for a = 1, #str do
373+
374-
					output = output + notif.width + (adjList[str:sub(a,a)] or 0)
374+
375
		end
376
		if cx == scr_x then
377
			termsetCursorPos(1,cy+1)
378-
			canvas.clear()
378+
379-
			local xadj, charadj, wordadj, t, r
379+
380-
			local x, y, words, txtwords, bgwords = 0, 0
380+
381-
			for n = math.min(#nList,16), 1, -1 do
381+
382-
				xadj, charadj = 0, 0
382+
383-
				y = y + 1
383+
384-
				x = 0
384+
	return lines
385-
				words = explode(" ",nList[n][1],_,true)
385+
386-
				txtwords = explode(" ",nList[n][1],nList[n][2],true)
386+
387-
				bgwords = explode(" ",nList[n][1],nList[n][3],true)
387+
388-
				local char, text, back
388+
389-
				local currentX = 0
389+
390-
				for w = 1, #words do
390+
391-
					char = words[w]
391+
392-
					text = txtwords[w]
392+
393-
					back = bgwords[w]
393+
394-
					if currentX + getWordWidth(char) > notif.wrapX then
394+
395-
						y = y + 1
395+
396-
						x = 2
396+
397-
						xadj = 0
397+
398-
						currentX = x * notif.width
398+
399
	["k"] = "krazy"	--Makes the font krazy!
400-
					for cx = 1, #char do
400+
401-
						x = x + 1
401+
402-
						charadj = (adjList[char:sub(cx,cx)] or 0)
402+
403-
						r = canvas.addRectangle(xadj+1+(x-1)*notif.width, 1+(y-1)*notif.height, charadj+notif.width, notif.height)
403+
404-
						if back:sub(cx,cx) ~= " " then
404+
405-
							r.setAlpha(notif.alpha * nList[n][5])
405+
406-
							r.setColor(table.unpack(colorTranslate[back:sub(cx,cx)]))
406+
407
		"|",
408-
							r.setAlpha(100 * nList[n][5])
408+
409-
							r.setColor(table.unpack(colorTranslate["7"]))
409+
410
		":",
411-
						drawEdgeLine(y,notif.alpha * nList[n][5])
411+
412-
						t = canvas.addText({xadj+1+(x-1)*notif.width,2+(y-1)*notif.height}, char:sub(cx,cx))
412+
413-
						t.setAlpha(notif.alpha * nList[n][5])
413+
414-
						t.setColor(table.unpack(colorTranslate[text:sub(cx,cx)]))
414+
415-
						xadj = xadj + charadj
415+
416-
						currentX = currentX + charadj+notif.width
416+
417
		"m",
418
		"X",
419-
				if doCountDown then
419+
420-
					if nList[n][4] > 1 then
420+
421-
						nList[n][4] = nList[n][4] - 1
421+
422
		"@",
423-
						if nList[n][5] > 0 then
423+
424-
							while true do
424+
425-
								nList[n][5] = math.max(nList[n][5] - 0.2, 0)
425+
426-
								notif.displayNotifications(false)
426+
427-
								if nList[n][5] == 0 then break else sleep(0.05) end
427+
428
end
429
for k,v in pairs(kraziez) do
430-
						table.remove(nList,n)
430+
431
		kraziez[kraziez[k][a]] = v
432
	end
433
end
434
if _VERSION then
435
	for a = 1, 255 do
436
		if (a ~= 32) and (a ~= 13) and (a ~= 10) then
437
			kraziez["all"][#kraziez["all"]+1] = string.char(a)
438-
if not (peripheral.find("modem") or enchatSettings.emulateModem) then
438+
439-
	if WHISPER and _USERNAME then
439+
440-
		WHISPER(_USERNAME,"Tell the owner to stick a modem on the MCCI computer.")
440+
441
	for a = 33, 126 do
442-
		termsetBackgroundColor(ncs(colors.gray))
442+
443
	end
444-
		termclear()
444+
445-
		cwrite("Enchat"..(isBeta and " Beta " or " ").."requires a modem.",3)
445+
446-
		cwrite("Add one, or press a key.",4)
446+
447-
		sleep(0.1)
447+
local textToBlit = function(str) --returns output for term.blit, or blitWrap, with formatting codes for color selection. Modified for use specifically with Enchat.
448-
		local outcome = parallelwaitForAny(function() os.pullEvent("key") end, waitForModem)
448+
449-
		modems = {peripheral.find("modem")}
449+
450-
		if #modems == 0 then
450+
451-
			termsetBackgroundColor(colors.black)
451+
452-
			termsetCursorPos(1,scr_y)
452+
453
	local bgcode = "~"
454-
			sleep(0)
454+
455
	local doFormatting = true
456
	local usedformats = {}
457
	local txcol,bgcol = blit_names[termgetTextColor()], blit_names[termgetBackgroundColor()]
458
	local origTX,origBG = blit_names[termgetTextColor()], blit_names[termgetBackgroundColor()]
459
	local cx,cy
460
	local moveOn = function(tx,bg)
461-
	if chan then
461+
		if isKrazy and (str:sub(p,p) ~= " ") and doFormatting then
462-
		for a = 1, #modems do
462+
463-
			modems[a].open(chan)
463+
464
			else
465
				output = output..kraziez.all[math.random(1,#kraziez.all)]
466
			end
467
		else
468
			output = output..str:sub(p,p)
469-
	if chan then 
469+
470-
		for a = 1, #modems do
470+
		txcolorout = txcolorout..(doFormatting and tx or origTX)
471-
			modems[a].close(chan)
471+
		bgcolorout = bgcolorout..(doFormatting and bg or origBG)
472
	end
473
	while p <= #str do
474
		if str:sub(p,p) == txcode then
475
			if colors_names[str:sub(p+1,p+1)] and doFormatting then
476
				txcol = str:sub(p+1,p+1)
477
				usedformats.txcol = true
478
				p = p + 1
479
			elseif codeNames[str:sub(p+1,p+1)] then
480
				if str:sub(p+1,p+1) == "r" and doFormatting then
481
					txcol = blit_names[termgetTextColor()]
482
					isKrazy = false
483
					p = p + 1
484-
		if termcurrent().setVisible and enchatSettings.useSetVisible then
484+
485
					doFormatting = false
486
					p = p + 1
487
				elseif str:sub(p+1,p+1) == "}" and (not doFormatting) then
488
					doFormatting = true
489
					p = p + 1
490
				elseif str:sub(p+1,p+1) == "k" and doFormatting then
491
					isKrazy = true
492
					usedformats.krazy = true
493
					p = p + 1
494
				else
495
					moveOn(txcol,bgcol)
496
				end
497
			else
498
				moveOn(txcol,bgcol)
499
			end
500
			p = p + 1
501
		elseif str:sub(p,p) == bgcode then
502
			if colors_names[str:sub(p+1,p+1)] and doFormatting then
503
				bgcol = str:sub(p+1,p+1)
504
				usedformats.bgcol = true
505-
	["pearl"] = colors.white,
505+
506-
	["aryan"] = colors.white,
506+
507-
	["#f0f0f0"] = colors.white,
507+
				bgcol = blit_names[termgetBackgroundColor()]
508
				p = p + 1
509-
	["carrot"] = colors.orange,
509+
510-
	["#f2b233"] = colors.orange,
510+
511
				p = p + 1
512-
	["hotpink"] = colors.magenta,
512+
513
				moveOn(txcol,bgcol)
514
			end
515-
	["#e57fd8"] = colors.magenta,
515+
516
		else
517
			moveOn(txcol,bgcol)
518-
	["skyblue"] = colors.lightBlue,
518+
519-
	["#99b2f2"] = colors.lightBlue,
519+
520
	end
521
	return output, txcolorout, bgcolorout, usedformats
522
end
523-
	["cowardice"] = colors.yellow,
523+
524-
	["#dede6c"] = colors.yellow,
524+
525
	local scr_x,scr_y = termgetSize()
526
	local sx,sy = termgetCursorPos()
527
	local cursor = 1
528-
	["slime"] = colors.lime,
528+
529-
	["#7fcc19"] = colors.lime,
529+
530
	termsetCursorBlink(true)
531-
	["lightishred"] = colors.pink,
531+
532
	while true do
533-
	["communist"] = colors.pink,
533+
534-
	["#f2b2cc"] = colors.pink,
534+
535
			pleaseDoFunc = true
536
		elseif evt == "key" then
537-
	["#4c4c4c"] = colors.gray,
537+
538
				if not noNewLine then
539
					write("\n")
540
				end
541
				termsetCursorBlink(false)
542-
	["#999999"] = colors.lightGray,
542+
543
			elseif key == keys.left then
544
				if cursor-1 >= 1 then
545-
	["#4c99b2"] = colors.cyan,
545+
546
				end
547
			elseif key == keys.right then
548-
	["obsidian"] = colors.purple,
548+
549-
	["#b266e5"] = colors.purple,
549+
550
				end
551
			elseif key == keys.up then
552-
	["blueberry"] = colors.blue,
552+
553-
	["x"] = colors.blue,
553+
554-
	["#3366bb"] = colors.blue,
554+
555
					rite((" "):rep(#output))
556
					output = rHistory[rCursor] or ""
557-
	["dirt"] = colors.brown,
557+
558-
	["#7f664c"] = colors.brown,
558+
559
				end
560
			elseif key == keys.down then
561-
	["#57a64e"] = colors.green,
561+
562
				rite((" "):rep(#output))
563
				if rCursor < #rHistory then
564-
	["marinara"] = colors.red,
564+
565-
	["zero"] = colors.red,
565+
566-
	["communism"] = colors.red,
566+
567-
	["#cc4c4c"] = colors.red,
567+
568
				else
569-
	["dark"] = colors.black,
569+
570-
	["coal"] = colors.black,
570+
571-
	["onyx"] = colors.black,
571+
572-
	["#191919"] = colors.black,
572+
573
			elseif key == keys.backspace then
574
				if cursor > 1 and #output > 0 then
575
					output = output:sub(1,cursor-2)..output:sub(cursor)
576
					cursor = cursor - 1
577
					pleaseDoFunc = true
578
				end
579
			elseif key == keys.delete then
580
				if #output:sub(cursor,cursor) == 1 then
581
					output = output:sub(1,cursor-1)..output:sub(cursor+1)
582
					pleaseDoFunc = true
583
				end
584
			end
585
		elseif evt == "char" or evt == "paste" then
586
			output = output:sub(1,cursor-1)..key..output:sub(cursor+(#key-1))
587
			cursor = cursor + #key
588
			pleaseDoFunc = true
589
		end
590
		local pOut = (output or ""):sub(math.max( 1,(#textToBlit(output)+sx)-scr_x) )
591-
			if not colormode then
591+
592-
				if (col ~= colors.white) and (col ~= colors.black) then
592+
593-
					return (grayAllowed and (col == colors.lightGray) or (col == colors.gray))
593+
594
				doFunc(output)
595
			end
596
			termsetCursorPos(sx,sy)
597
			if repchar then
598
				rite(repchar:sub(1,1):rep(#pOut))
599
			else
600
				rite(pOut)
601
			end
602
			termwrite(" ")
603
		end
604
		termsetCursorPos(sx+cursorAdjFunc(pOut)+cursor-math.max( 1,(#textToBlit(output)+sx)-scr_x),sy)
605
	end
606
end
607
608
local generateEncy = function()
609
	modems = {peripheral.find("modem")}
610
	modemClose(channel)
611
	channel = 0
612
	for a = 1, #encKey do
613
		channel = channel + string.byte(string.sub(encKey,a,a))
614
	end
615
	if channel >= 65535 then
616
		error("Bad key! Use a smaller one.")
617
	end
618
	modemOpen(channel)
619
	checksum = "ENCMAIL" --Used to eliminate gibberish messages securely, based on the key.
620
	for a = 1, #encKey do
621
		checksum = checksum..string.byte(string.sub(encKey,a,a))
622
	end
623
	checksum = encrite(checksum,encKey)
624
end
625
626-
				output[#output+1] = {text:sub(a,a),txt:sub(a,a),bg:sub(a,a)}
626+
627
	if textToBlit(yourName) == "con" or textToBlit(yourName) == "*" then return printError("Not that name!") end
628
end
629
630
local cf = function(txt) --contextual filter
631
	if enchatSettings.doColorize then
632
		return txt
633
	else
634
		return textToBlit(txt)
635
	end
636
end
637
638
local writef = function(txt,noWrite)
639
	if enchatSettings.doColorize then
640
		local text, textCol, bgCol, usedformats = textToBlit(txt)
641
		local out = blitWrap(text,textCol,bgCol,noWrite)
642-
	return lines, output
642+
643
	else
644
		return write(txt), #txt, {}
645
	end
646
end
647
648
local _ftlen = function(text)
649
	return #textToBlit(text)-#text
650
end
651
652
local clearLines = function(top, bottom)
653
	for a = top, bottom do
654
		termsetCursorPos(1,a)
655
		termclearLine()
656
	end
657
end
658
659
scroll = 1
660
doScroll = true
661
662
local urkrazy,_ = false
663
local redrawScreen = function() --renders the chat and other things that change when scrolling.
664
	tsv(false)
665
	local prevX, prevY = termgetCursorPos()
666
	local _logold = _log
667
	_log,log = {},{}
668
	for a = 1, #chatlog do
669
		if not chatlog[a][3] then
670
			_log[#_log+1] = {"",false}
671
		end
672
		if chatlog[a][4] == true then
673
			_log[#_log+1] = {"<"..chatlog[a][1].."> "..chatlog[a][2],false}
674
		else
675
			_log[#_log+1] = {cf("<"..chatlog[a][1].."&r~r> "..chatlog[a][2]),true}
676
		end
677
	end
678
	if not doScroll then
679
		scroll = scroll + (#_log - #_logold)
680
	end
681
	for a = 1, #_log-(scroll-1) do
682
		log[#log+1] = _log[a]
683
	end
684
	termsetCursorPos(1,1)
685
	termsetBackgroundColor(palate.bg)
686
	termsetTextColor(palate.txt)
687
	termwrite(string.rep(" ",scr_x*(scr_y-2)))
688
	local midPoint = {
689
		scr_x / 2,
690
		scr_y / 2,
691
	}
692-
if tonumber(_CC_VERSION or 0) >= 1.76 then
692+
693
	clearLines(1,scr_y-2)
694
	termsetCursorPos(1,scr_y)
695
	termclearLine()
696
	local indent = 1 --in case any line is greater than the length of the screen
697
	local indentIn = 0 --in the same case, mid writing
698
	for a = 1, #log do
699
		if log[a][2] then
700
			indent = indent + writef(log[a][1],true)
701
		else
702
			indent = indent + math.floor(#log[a][1]/scr_x)
703
		end
704-
local moveOn
704+
705-
local textToBlit = function(str,onlyString,initTxt,initBg) --returns output for term.blit, or blitWrap, with formatting codes for color selection. Modified for use specifically with Enchat.
705+
706-
	if (not str) then
706+
707-
		if onlyString then
707+
		termsetCursorPos(1,((((scr_y-1)+a-#log))-indent)+indentIn)
708-
			return ""
708+
709
			indentIn = indentIn + writef(log[a][1],true)
710-
			return "","","",{}
710+
			_,_,urkrazy = writef(log[a][1],false)
711
			hasKrazy = hasKrazy or (urkrazy.krazy or false)
712
		else
713-
	str = tostring(str)
713+
714
			termwrite(log[a][1])
715
		end
716
	end
717
	termsetCursorPos(scr_x,scr_y)
718
	if doScroll then writef("&8.") else termwrite(" ") end
719
	termsetCursorPos(prevX,prevY)
720
	tsv(true)
721
end
722
723-
	local txcol,bgcol = initTxt or blit_names[termgetTextColor()], initBg or  blit_names[termgetBackgroundColor()]
723+
724-
	local origTX,origBG = initTxt or blit_names[termgetTextColor()], initBg or blit_names[termgetBackgroundColor()]
724+
	if (#modems > 0) then modemTransmit(channel, channel, {cry = true, cs = encode(checksum)}) end --ping!
725
	while true do
726-
	moveOn = function(tx,bg)
726+
727-
		if isKrazy and (str:sub(p,p) ~= " ") then -- and doFormatting then
727+
728
			if type(evt[5].tears) == "table" then evt[5].tears = decode(evt[5].tears) end
729
			if type(evt[5].tears) == "string" and decrite(decode(evt[5].cs),encKey) == decrite(checksum,encKey) then
730
				local tear = decrite(evt[5].tears,encKey)
731
				playerList[tear] = true
732
			end
733
		end
734
	end
735
end
736-
		txcolorout = txcolorout..tx --(doFormatting and tx or origTX)
736+
737-
		bgcolorout = bgcolorout..bg --(doFormatting and bg or origBG)
737+
local handleCommand = function(commie)
738
	commie = commie or {}
739
	local command = commie[1] or ""
740
	local argument = commie
741
	if #commie > 0 then
742
		table.remove(argument,1)
743
		argument = tableconcat(argument," ") or ""
744
	else
745
		argument = ""
746
	end
747-
					txcol = origTX
747+
	local commandTable
748
	commandTable = {
749
		["exit"] = function() --why would you want to leave??
750
			endMode = 0
751
			return "exit"
752
		end,
753
		["key"] = function() 
754
			if #argument > 0 then
755
				if argument == encKey then return end
756
				os.queueEvent("enchat_send", "con", yourName.."&r~r has left.",encKey)
757
				sleep(0)
758
				encKey = argument
759
				generateEncy()
760
				os.queueEvent("enchat_send", "con", yourName.."&r~r moseyed on over.",encKey)
761
				logadd("*","Key changed. (channel: "..channel.."&r)",true)
762
			else
763
				generateEncy() --in case you break and reattach a modem, this should fix it right up
764
				logadd("*","Modem Channel: "..channel,false,true)
765
				logadd("*","Key: "..strcapsule(encKey),true,true)
766
			end
767
			redrawScreen()
768
		end,
769
		["heil"] = function() --please don't tell me that you're offended, or I'll get offended
770
			local heilTable = {
771
				"Cobra",
772
				"this",
773-
				bgcol = origBG
773+
774
				"unto me",
775
				"dan200",
776
				"myself",
777
				"!",
778
				"oeed",
779
				"Exerro",
780
				"Kepler",
781
				"Danny",
782
				"Bagel",
783
				"Roger",
784
				"King Porky",
785
			}
786
			local hailer
787-
	if onlyString then
787+
788-
		return output
788+
789
			os.queueEvent("enchat_send", yourName, mess)
790-
		return output, txcolorout, bgcolorout, usedformats
790+
			logadd("con","You heiled "..hailer.."!",false)
791
			redrawScreen()
792
		end,
793
		["help"] = function() --I would call it "man", but there's only so much you can write about a two-argument function
794-
local logadd = function(name,msg,newline,stopFormatting,doNotSay)
794+
795
			for k,v in pairs(commandTable) do
796-
	if (WHISPER and _USERNAME) and (not doNotSay) then
796+
				strtime = tostring(math.floor(os.time()/timedivisor))
797-
		WHISPER(_USERNAME,textToBlit(table.concat({name,": ",msg}),true))
797+
				logadd("*","&0/&4"..k,a)
798
				a = true
799-
	if enchatSettings["doNotif"] and canvas then
799+
800-
		local c,t,b
800+
801-
		if name then
801+
802-
			c,t,b = textToBlit(table.concat({"<",name,"&r~r> ",msg}),nil,"0"," ")
802+
803
			_log = {}
804-
			c,t,b = textToBlit(msg,nil,"0"," ")
804+
805
			chatlog = {}
806-
		notif.newNotification(c,t,b,notif.time*4)
806+
807
		end,
808
		["cry"] = function() --your annoying tears streaming from your stupid fat face attracts a list of other people
809
			playerList = {}
810
			logadd("con","You cried loudly!",true)
811
			redrawScreen()
812
			parallelwaitForAny(_getTears, function() sleep(0.5) return end)
813
			_list = {}
814
			for k,v in pairs(playerList) do
815
				tableinsert(_list,k)
816
			end
817
			if #_list > 0 then
818
				logadd("con",tableconcat(_list,"&r~r, ").."&r~r responded!",true)
819
			else
820
				logadd("con","&eBut nobody came.",true)
821
			end
822
			redrawScreen()
823
		end,
824
		["me"] = function() -- * EldidiStroyrr is dashingly handsome
825
			os.queueEvent("enchat_send", "*", "~r"..yourName.."~r&2 "..argument)
826
			logadd("*","~r"..yourName.."~r&2 "..argument,false)
827
			redrawScreen()
828
		end,
829
		["colors"] = function()
830
			logadd("*","~0&f0~1&01~22~33~44~55~66~77~88~99~aa~bb~cc~dd~ee~ff",false)
831
			logadd("*","'&' for text, '~' for background.",false)
832
			redrawScreen()
833
		end,
834
		["ping"] = function() --what do you mean this command is useless
835
			logadd("*",(argument ~= "") and argument or "Pong!",false)
836
			redrawScreen()
837-
			elseif key == keys.home then
837+
838-
				cursor = 1
838+
839-
			elseif key == keys["end"] then
839+
840-
				cursor = #output+1
840+
			if argument:gsub("%s","") == "beta" then
841
				url = "https://pastebin.com/raw/4a6NZaMZ"
842
			else
843
				url = "https://pastebin.com/raw/JtgbWdV5"
844
			end
845
			if shell then
846
				cfile = shell.getRunningProgram()
847
			else
848
				--termsetBackgroundColor(palate.bg)
849
				--termsetTextColor((palate.txt ~= colors.yellow) and colors.yellow or colors.black)
850
				--cwrite("Download where?",scr_y,true)
851
				logadd("con","&4Download where?",true)
852
				scroll = 1
853
				redrawScreen()
854
				termsetCursorPos(1,scr_y-1)
855
				termsetBackgroundColor(colors.lightGray)
856
				termsetTextColor(palate.chattxt)
857
				termclearLine()
858
				write(":")
859
				termsetBackgroundColor(palate.chatbg)
860
				cfile = read()
861
			end
862
			if fs.isReadOnly(cfile) then
863
				logadd("*","Unable to update to &4read-only directory.&r",true)
864
				redrawScreen()
865
				return
866
			end
867
			if not http then
868
				logadd("*","&4HTTP is disabled.&r Ask an admin to enable it.",true)
869
				redrawScreen()
870
				return
871
			else
872
				if not http.checkURL(url) then
873
					logadd("*","&4It appears the download URL is whitelisted.&r &cPlease slap your admin in their stupid face.",true)
874
					redrawScreen()
875
					return
876
				end
877
			end
878
			--termsetBackgroundColor(palate.bg)
879
			--termsetTextColor((palate.txt ~= colors.yellow) and colors.yellow or colors.black)
880
			--cwrite("Downloading...",scr_y,true)
881
			logadd("con","&4Downloading...",true)
882
			scroll = 1
883
			redrawScreen()
884
			local data = http.get(url)
885
			if not data then
886
				logadd("*","&4Couldn't connect to Pastebin.&r Sorry.",true)
887
				redrawScreen()
888
				return
889
			else
890
				local file = fs.open(cfile,"w")
891
				file.write(data.readAll())
892
				file.close()
893
				--cwrite("Yay! Relaunching.",scr_y,true)
894
				logadd("con","&4Yay! Relaunching.",true)
895
				scroll = 1
896
				redrawScreen()
897
				sleep(1)
898
				os.queueEvent("enchat_send", "con", yourName.."&r~r redownloaded the program.")
899
				sleep(0)
900-
	channel = fixedChannel and fixedChannel or channel
900+
901
				return "restart"
902
			end
903
		end,
904
		["whoami"] = function()
905
			if argument:lower() == "now" then
906
				logadd("*","You are still \""..yourName.."&r~r\"!",true)
907
			else
908
				logadd("*","You are \""..yourName.."&r~r\"!",true)
909-
	channel = fixedChannel and fixedChannel or channel
909+
910
			redrawScreen()
911-
	checksum = "" --Used to eliminate gibberish messages securely, based on the key.
911+
912
		["nick"] = function()
913
			if argument ~= "" then
914
				if argument ~= yourName then
915
					if #argument:gsub("%s","") > 0 then
916
						if #textToBlit(argument) < 20 then
917
							if textToBlit(argument) ~= "con" and textToBlit(argument) ~= "*" then
918
								os.queueEvent("enchat_send", "con", tostring(yourName.."&r~r is now known as "..strcapsule(argument.."&r~r")))
919
								logadd("*",yourName.."&r~r is now known as "..strcapsule(argument.."&r~r"),false)
920
								yourName = tostring(argument)
921
							else
922
								logadd("*","&4Not so fast!!",false)
923
							end
924
						else
925
							logadd("*","&4Maximum 20 non-formatting characters!",false)
926
						end
927
					else
928
						logadd("*","&4Choose a more substantial name.",false)
929
					end
930
				else
931
					logadd("*","&4That's already your name.",false)
932
				end
933
			else
934
				logadd("*","&4/nick <newname>",true)
935
			end
936-
		if noWrite then
936+
937-
			local cx,cy = termgetCursorPos()
937+
938-
			return math.floor((cx+#cf(txt))/scr_x), #cf(txt), {} --this is approximate, and might mess up with multiline strings
938+
939
			if argument:gsub("%s","") == "" then
940-
			return write(txt), #txt, {}
940+
941
			else
942
				argument = explode(" ",argument)
943
				if #argument == 1 then
944
					if argument[1]:gsub("%s",""):lower() == "reset" then
945
						palate = {
946-
	return enchatSettings.doColorize and (#textToBlit(text) - #text) or 0
946+
947
							txt = colors.white,
948
							chatbg = colors.white,
949
							chattxt = colors.black,
950
						}
951
						logadd("*","&4You cleansed your palate.",false)
952
					else
953
						logadd("*","&4Give me a color code next time.",false)
954
					end
955
				else
956
					if #argument > 2 then
957
						argument = {argument[1], tableconcat(argument," ",2)}
958
					end
959-
local urkrazy,spagh,_ = false
959+
960
					local newcol = argument[2]:lower()
961-
	if _USERNAME then
961+
962-
		return
962+
963
					else
964
						if not colors_strnames[newcol] then
965
							logadd("*","&4That isn't a valid color code. (0-f)")
966
						else
967
							palate[argument[1]] = colors_strnames[newcol]
968
							logadd("*","You have such a sense of style.",false)
969
						end
970
					end
971
				end
972
			end
973-
			if chatlog[a][1] then
973+
974-
				_log[#_log+1] = {table.concat({"<",chatlog[a][1],"> ",chatlog[a][2]}),false}
974+
975
	}
976-
				_log[#_log+1] = {chatlog[a][2],false}
976+
977
		return commandTable[command]()
978
	else
979-
			if chatlog[a][1] then
979+
980-
				_log[#_log+1] = {cf(table.concat({"<",chatlog[a][1],"&r~r> ",chatlog[a][2]})),true}
980+
981
end
982-
				_log[#_log+1] = {cf(chatlog[a][2]),true}
982+
983
local doAndBack = function(func)
984
	local backColor = termgetBackgroundColor()
985
	local textColor = termgetTextColor()
986
	local curX, curY = termgetCursorPos()
987
	local results = {func()}
988
	termsetBackgroundColor(backColor)
989
	termsetTextColor(textColor)
990
	termsetCursorPos(curX,curY)
991
	return tableunpack(results)
992
end
993-
	termsetBackgroundColor(ncs(palate.bg))
993+
994-
	termsetTextColor(ncs(palate.txt))
994+
local mainMenu = function()
995
	local options = {"Send","Inbox","Contacts","Back to terminal","Quit"}
996
	local cursor = 1
997
	local _rendermenu = function(c)
998
		for a = 1, #options do
999
			term.setCursorPos(2,(scr_y-#options)-1+a)
1000
			if a == c then
1001
				writef("&0> "..options[a])
1002
			else
1003
				writef("&7 "..options[a])
1004
			end
1005
		end
1006
	end
1007
	while true do
1008
		_rendermenu(cursor)
1009
		
1010
	end
1011
end
1012
1013
local renderAll = function()
1014
	while true do
1015-
		local ypos = ((((scr_y-1)+a-#log))-indent)+indentIn
1015+
		local result = mainMenu()
1016-
		termsetCursorPos(1,ypos)
1016+
1017
end
1018-
			spagh,_,urkrazy = writef(log[a][1],true)
1018+
1019-
			indentIn = indentIn + spagh
1019+
local receiveMessages = function()
1020-
			writef(log[a][1],false)
1020+
	local encMessage
1021-
			-- _,_,urkrazy = writef(log[a][1],false)
1021+
1022-
			hasKrazy = hasKrazy or (urkrazy.krazy and (ypos <= scr_y+2 and ypos >= 1)) or false
1022+
1023
		event, side, frequency, replyFrequency, message, distance = os.pullEvent()
1024
		if event == "modem_message" then
1025
			if distance ~= 0 then
1026
				if type(message) == "table" then
1027
					if message.cry and message.cs then --basically a ping thing
1028
						message.cs = decrite(decode(message.cs),encKey)
1029-
	if doScroll then writef(cf("&8.")) else termwrite(" ") end
1029+
1030
							modemTransmit(channel, channel, {tears = encode(encrite(yourName,encKey)), cs = encode(checksum)})
1031
						end
1032
					else
1033
						if message.name and message.msg and message.cs then
1034-
local dchecksum
1034+
1035
							message.cs = decrite(decode(message.cs),encKey)
1036-
	modemTransmit(channel, channel, {cry = true, cs = encode(checksum)}) --ping!
1036+
1037
							message.name = decode(message.name)
1038
							if type(message.name) == "string" and type(message.msg) == "string" and message.cs == decrite(checksum,encKey) then
1039
								local strtime = tostring(math.floor(os.time()/timedivisor))
1040
								local plainname, plainmsg = decrite(decrite(message.name,strtime),encKey), decrite(decrite(message.msg,strtime),encKey)
1041-
			if type(evt[5].tears) == "string" and decrite(decode(evt[5].cs),encKey) == dchecksum then
1041+
1042
								os.queueEvent("enchat_receive",message.name,encMessage)
1043
								doAndBack(redrawScreen)
1044
							end
1045
						end
1046
					end
1047
				end
1048
			end
1049-
local formatTable = function(tbl)
1049+
		--elseif event == "didScroll" then
1050
		--	doAndBack(redrawScreen)
1051
		elseif event == "peripheral" or event == "peripheral_detach" then --yaay
1052-
		output = table.concat({output," ",tostring(k)," = ",textutils.serialize(v),","})
1052+
1053
				generateEncy()
1054-
	return output:sub(2,-2)
1054+
1055
		end
1056
	end
1057-
local contextualQuote,custColor = function(judgetxt,txt)
1057+
1058-
	if type(judgetxt) == "string" then
1058+
1059-
		return table.concat({"'",txt,"'"})
1059+
local sendMessages = function()
1060
	while true do
1061
		local event, name, message = os.pullEvent("enchat_send",key)
1062
		local eName = encrite(encrite(tostring(name),key or encKey),tostring(math.floor(os.time()/timedivisor)))
1063
		local eMessage = encrite(encrite(tostring(message),key or encKey),tostring(math.floor(os.time()/timedivisor)))
1064
		local sendmsg = {
1065-
local enchatSend = function(name, message)
1065+
			name = encode(eName),
1066-
	local eName = encrite(encrite(tostring(name),key or encKey),tostring(math.floor(os.time()/timedivisor)))
1066+
			msg = encode(eMessage),
1067-
	local eMessage = encrite(encrite(tostring(message),key or encKey),tostring(math.floor(os.time()/timedivisor)))
1067+
			cs = encode(checksum),
1068-
	local sendmsg = {
1068+
		}
1069-
		name = encode(eName),
1069+
		modemTransmit(channel, channel, sendmsg)
1070-
		msg = encode(eMessage),
1070+
1071-
		cs = encode(checksum),
1071+
1072
1073-
	modemTransmit(channel, channel, sendmsg)
1073+
if termisColor() then
1074
	colormode = true
1075
	grayAllowed = true
1076-
local handleCommand = function(commie) --"I was only taking orders"
1076+
1077
	colormode = false
1078
	if _VERSION then
1079
		grayAllowed = true
1080
	else
1081
		grayAllowed = false
1082
	end
1083
end
1084
1085
termsetBackgroundColor(colors.gray)
1086-
	local commandTable,commandHelp
1086+
termclear()
1087-
	commandHelp = {
1087+
termsetCursorPos(1,1)
1088-
		["exit"] = "Exits enchat, I think.",
1088+
1089-
		["key"] = "Displays the encryption key and modem channel used. Add an argument to redefine the key.",
1089+
1090-
		["heil"] = "HEIL a random name from a list, or choose your own Fuhrer!",
1090+
1091-
		["help"] = "Displays a list of commands, or displays a blurb about a specific command.",
1091+
		termsetBackgroundColor(colors.gray)
1092-
		["clear"] = "Clears your inventory. Kidding. It actually wipes the log of messages.",
1092+
1093-
		["cry"] = "Cry like a bitch to get a list of all other Enchat clients that you can communicate with.",
1093+
1094-
		["me"] = "Make a personalized message, like '* you is gr8 m8'",
1094+
1095-
		["colors"] = "Shows a list of colors to format your messages with.",
1095+
1096-
		["ping"] = "Pong!",
1096+
		termsetBackgroundColor(colors.lightGray)
1097-
		["update"] = "Updates Enchat to the latest version from Pastebin. For an argument, type 'beta' or 'stable' (or none at all) to update to the right build.",
1097+
1098-
		["whoami"] = "Tells you your username.",
1098+
1099-
		["nick"] = "Takes one argument, which is your new nickname. Accepts color codes and everything.",
1099+
1100-
		["palate"] = "Change the color of certain elements of the Enchat interface. Accepts normal color names, but also things like blood, grass, piss...",
1100+
1101-
		["set"] = "Set a config variable to a custom value for the current session.",
1101+
1102-
		["about"] = "Tells you a blurb about Enchat.",
1102+
1103-
		["yourself"] = "Don't mind if I do!",
1103+
1104
if not yourName then
1105
	write("\n")
1106
	local posX, posY = termgetCursorPos()
1107
	local prevX,prevY = 1,1
1108
	local namePrompt = function()
1109
		termsetCursorPos(prevX,prevY)
1110
		termsetBackgroundColor(colors.lightGray)
1111
		termsetTextColor(colors.black)
1112
		termclearLine()
1113-
				enchatSend("*", yourName.."&r~r has left.",encKey)
1113+
1114
	end
1115
	repeat
1116
		termsetBackgroundColor(colors.gray)
1117-
				enchatSend("*", yourName.."&r~r moseyed on over.",encKey)
1117+
1118-
				logadd("*","Key changed. (channel: "..channel.."&r~r)",true)
1118+
1119
		termclearLine()
1120
		cwrite("Enter your name:\n",posY)
1121
		prevX,prevY = termgetCursorPos()
1122
		if enchatSettings.doColorize then
1123
			termsetTextColor(colors.lightGray)
1124
			cwrite("Color codes:",scr_y-3)
1125
			cwrite("(&text,~backg.)",scr_y-2)
1126
			termsetCursorPos((scr_x/2)-8,scr_y-1)
1127
			termsetBackgroundColor(colors.gray)
1128
			termclearLine()
1129
			blitWrap(textToBlit("~0&f0~1&01~22~33~44~55~66~77~88~99~aa~bb~cc~dd~ee~ff"))
1130
			termsetCursorPos(prevX,prevY)
1131-
				"Gospel",
1131+
1132-
				"Grave",
1132+
		termsetBackgroundColor(colors.lightGray)
1133-
				"WWW! Delete",
1133+
1134-
				"Lord Wily",
1134+
1135-
				"DanTwoHundred",
1135+
1136-
				"SquidDev",
1136+
		yourName = enchatSettings.fancyMsg and funcread(nil,{},namePrompt,false,writef,_ftlen) or read()
1137-
				"the Unicode Consortium",
1137+
1138-
				"the MATE developers",
1138+
			termsetBackgroundColor(colors.gray)
1139-
				"those golden few who play Battle Network",
1139+
1140-
				"to 10 people to get a free iPhone X",
1140+
1141-
				"or be heiled",
1141+
1142-
				"Sakurai",
1142+
1143-
				"Inti Creates",
1143+
1144-
				"that one guy who got struck by lightning a bunch of times or something",
1144+
termsetBackgroundColor(colors.gray)
1145
termsetTextColor(colors.white)
1146
1147
generateEncy()
1148
1149
local getScrolling = function()
1150
	local oldScroll
1151
	scroll = 1
1152
	doScroll = true
1153
	while true do
1154
		local _,dir,x,y = os.pullEvent("mouse_scroll")
1155
		oldScroll = scroll
1156
		if dir == (enchatSettings.reverseScroll and 1 or -1) then
1157
			if scroll < #_log-1 then
1158-
			enchatSend(yourName, mess)
1158+
				scroll = scroll + 1
1159-
			logadd("*","You heiled "..hailer.."!",false)
1159+
1160
			end
1161
		elseif dir == (enchatSettings.reverseScroll and -1 or 1) then
1162
			if scroll > 1 then
1163
				scroll = scroll - 1
1164-
			local arguments = explode(" ",argument) --I should really be more clear as to what variables are
1164+
				if scroll == 1 then
1165-
			if commandHelp[arguments[1]] then
1165+
					doScroll = true
1166-
				logadd("*",commandHelp[arguments[1]] or "No help text? Odd.")
1166+
1167
			end
1168-
				for k,v in pairs(commandTable) do
1168+
1169-
					logadd("*","&0/&4"..k,a)
1169+
		if oldScroll ~= scroll then
1170-
					a = true
1170+
			os.queueEvent("didScroll",scroll)
1171
		end
1172
	end
1173
end
1174
1175
local redrawForKrazy = function()
1176
	while true do
1177
		if hasKrazy then
1178
			redrawScreen()
1179
			os.queueEvent("redrawprompt")
1180
		else
1181-
			nList = {}
1181+
			sleep(0.2)
1182
		end
1183
		sleep(0.2)
1184
	end
1185-
			logadd("*","You cried loudly!",true)
1185+
1186
1187-
			parallelwaitForAny(_getTears, function() sleep(0.75) return end)
1187+
os.queueEvent("enchat_send", "con", yourName.."&r~r moseyed on over.")
1188
1189
local funcList = {
1190
	receiveMessages,
1191
	sendMessages,
1192
	renderAll,
1193-
				logadd("*",tableconcat(_list,"&r~r, ").."&r~r responded!",true)
1193+
	getScrolling,
1194
	redrawForKrazy,
1195-
				logadd("*","&eBut nobody came.",true)
1195+
1196
parallelwaitForAny(tableunpack(funcList))
1197
if endMode == 1 then
1198
	if shell then
1199
		shell.run(strcapsule(cfile),strcapsule(encKey),strcapsule(yourName))
1200-
			enchatSend("*", "~r"..yourName.."~r&2 "..argument)
1200+
1201
		loadfile(cfile)(encKey,yourName)
1202
	end
1203
else
1204
	if modem then modemClose(channel) end
1205
	termsetCursorPos(1,scr_y)
1206
	termsetBackgroundColor(colors.black)
1207
	termclearLine()
1208
end