View difference between Paste ID: 4KnCPupW and sPpkBP9v
SHOW: | | - or go back to the newest paste.
1
--[[
2
IRC Controlled Turtle Scipt
3
Lion4ever, 2014
4
http://pastebin.com/sPpkBP9v
5
6
7
Heavyly base on the CC IRC Client from:
8
Matti Vapa, 2014
9
https://github.com/mattijv/IRCCC/
10
http://pastebin.com/gaSL8HZC
11
12
This program is released under the MIT license.
13
14
]]--
15
16
--Preventing second instance (but not third):
17
if isRunning then
18
	isRunning = false --leaving no traces
19
	return false
20
end
21
isRunning = true
22
23
-- look at the source of the qwebirc webchat login page and take the values
24
-- for baseUrl and dynamicBaseUrl for use here
25
-- examples for espernet and quakenet
26
27
local baseUrl = "http://webchat.esper.net/"
28
local dynamicUrl = ""
29
--local baseUrl = "http://webchat.quakenet.org/"
30
--local dynamicUrl = "dynamic/leibniz/"
31
32
33
--------------------------------------------------------------------------------
34
--------------------------------------------------------------------------------
35
-- JSON4Lua: JSON encoding / decoding support for the Lua language.
36
-- json Module.
37
-- Author: Craig Mason-Jones
38
-- Homepage: http://json.luaforge.net/
39
-- Version: 0.9.40
40
-- This module is released under the MIT License (MIT).
41
 
42
-- edited for brevity
43
 
44
local base = _G
45
local decode_scanArray
46
local decode_scanComment
47
local decode_scanConstant
48
local decode_scanNumber
49
local decode_scanObject
50
local decode_scanString
51
local decode_scanWhitespace
52
local encodeString
53
local isArray
54
local isEncodable
55
local function encode (v)
56
  -- Handle nil values
57
  if v==nil then
58
    return "null"
59
  end
60
 
61
  local vtype = base.type(v)  
62
 
63
  -- Handle strings
64
  if vtype=='string' then    
65
    return '"' .. encodeString(v) .. '"'            -- Need to handle encoding in string
66
  end
67
 
68
  -- Handle booleans
69
  if vtype=='number' or vtype=='boolean' then
70
    return base.tostring(v)
71
  end
72
 
73
  -- Handle tables
74
  if vtype=='table' then
75
    local rval = {}
76
    -- Consider arrays separately
77
    local bArray, maxCount = isArray(v)
78
    if bArray then
79
      for i = 1,maxCount do
80
        table.insert(rval, encode(v[i]))
81
      end
82
    else        -- An object, not an array
83
      for i,j in base.pairs(v) do
84
        if isEncodable(i) and isEncodable(j) then
85
          table.insert(rval, '"' .. encodeString(i) .. '":' .. encode(j))
86
        end
87
      end
88
    end
89
    if bArray then
90
      return '[' .. table.concat(rval,',') ..']'
91
    else
92
      return '{' .. table.concat(rval,',') .. '}'
93
    end
94
  end
95
 
96
  -- Handle null values
97
  if vtype=='function' and v==null then
98
    return 'null'
99
  end
100
 
101
  base.assert(false,'encode attempt to encode unsupported type ' .. vtype .. ':' .. base.tostring(v))
102
end
103
 
104
local function decode(s, startPos)
105
  startPos = startPos and startPos or 1
106
  startPos = decode_scanWhitespace(s,startPos)
107
  base.assert(startPos<=string.len(s), 'Unterminated JSON encoded object found at position in [' .. s .. ']')
108
  local curChar = string.sub(s,startPos,startPos)
109
  -- Object
110
  if curChar=='{' then
111
    return decode_scanObject(s,startPos)
112
  end
113
  -- Array
114
  if curChar=='[' then
115
    return decode_scanArray(s,startPos)
116
  end
117
  -- Number
118
  if string.find("+-0123456789.e", curChar, 1, true) then
119
    return decode_scanNumber(s,startPos)
120
  end
121
  -- String
122
  if curChar==[["]] or curChar==[[']] then
123
    return decode_scanString(s,startPos)
124
  end
125
  if string.sub(s,startPos,startPos+1)=='/*' then
126
    return decode(s, decode_scanComment(s,startPos))
127
  end
128
  -- Otherwise, it must be a constant
129
  return decode_scanConstant(s,startPos)
130
end
131
 
132
local function null()
133
  return null -- so json.null() will also return null ;-)
134
end
135
 
136
 
137
function decode_scanArray(s,startPos)
138
  local array = {}      -- The return value
139
  local stringLen = string.len(s)
140
  base.assert(string.sub(s,startPos,startPos)=='[','decode_scanArray called but array does not start at position ' .. startPos .. ' in string:\n'..s )
141
  startPos = startPos + 1
142
  -- Infinite loop for array elements
143
  repeat
144
    startPos = decode_scanWhitespace(s,startPos)
145
    base.assert(startPos<=stringLen,'JSON String ended unexpectedly scanning array.')
146
    local curChar = string.sub(s,startPos,startPos)
147
    if (curChar==']') then
148
      return array, startPos+1
149
    end
150
    if (curChar==',') then
151
      startPos = decode_scanWhitespace(s,startPos+1)
152
    end
153
    base.assert(startPos<=stringLen, 'JSON String ended unexpectedly scanning array.')
154
    object, startPos = decode(s,startPos)
155
    table.insert(array,object)
156
  until false
157
end
158
 
159
function decode_scanComment(s, startPos)
160
  base.assert( string.sub(s,startPos,startPos+1)=='/*', "decode_scanComment called but comment does not start at position " .. startPos)
161
  local endPos = string.find(s,'*/',startPos+2)
162
  base.assert(endPos~=nil, "Unterminated comment in string at " .. startPos)
163
  return endPos+2  
164
end
165
 
166
function decode_scanConstant(s, startPos)
167
  local consts = { ["true"] = true, ["false"] = false, ["null"] = nil }
168
  local constNames = {"true","false","null"}
169
 
170
  for i,k in base.pairs(constNames) do
171
    --print ("[" .. string.sub(s,startPos, startPos + string.len(k) -1) .."]", k)
172
    if string.sub(s,startPos, startPos + string.len(k) -1 )==k then
173
      return consts[k], startPos + string.len(k)
174
    end
175
  end
176
  base.assert(nil, 'Failed to scan constant from string ' .. s .. ' at starting position ' .. startPos)
177
end
178
 
179
function decode_scanNumber(s,startPos)
180
  local endPos = startPos+1
181
  local stringLen = string.len(s)
182
  local acceptableChars = "+-0123456789.e"
183
  while (string.find(acceptableChars, string.sub(s,endPos,endPos), 1, true)
184
        and endPos<=stringLen
185
        ) do
186
    endPos = endPos + 1
187
  end
188
  local stringValue = 'return ' .. string.sub(s,startPos, endPos-1)
189
  local stringEval = base.loadstring(stringValue)
190
  base.assert(stringEval, 'Failed to scan number [ ' .. stringValue .. '] in JSON string at position ' .. startPos .. ' : ' .. endPos)
191
  return stringEval(), endPos
192
end
193
 
194
function decode_scanObject(s,startPos)
195
  local object = {}
196
  local stringLen = string.len(s)
197
  local key, value
198
  base.assert(string.sub(s,startPos,startPos)=='{','decode_scanObject called but object does not start at position ' .. startPos .. ' in string:\n' .. s)
199
  startPos = startPos + 1
200
  repeat
201
    startPos = decode_scanWhitespace(s,startPos)
202
    base.assert(startPos<=stringLen, 'JSON string ended unexpectedly while scanning object.')
203
    local curChar = string.sub(s,startPos,startPos)
204
    if (curChar=='}') then
205
      return object,startPos+1
206
    end
207
    if (curChar==',') then
208
      startPos = decode_scanWhitespace(s,startPos+1)
209
    end
210
    base.assert(startPos<=stringLen, 'JSON string ended unexpectedly scanning object.')
211
    -- Scan the key
212
    key, startPos = decode(s,startPos)
213
    base.assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
214
    startPos = decode_scanWhitespace(s,startPos)
215
    base.assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
216
    base.assert(string.sub(s,startPos,startPos)==':','JSON object key-value assignment mal-formed at ' .. startPos)
217
    startPos = decode_scanWhitespace(s,startPos+1)
218
    base.assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
219
    value, startPos = decode(s,startPos)
220
    object[key]=value
221
  until false   -- infinite loop while key-value pairs are found
222
end
223
 
224
function decode_scanString(s,startPos)
225
  base.assert(startPos, 'decode_scanString(..) called without start position')
226
  local startChar = string.sub(s,startPos,startPos)
227
  base.assert(startChar==[[']] or startChar==[["]],'decode_scanString called for a non-string')
228
  local escaped = false
229
  local endPos = startPos + 1
230
  local bEnded = false
231
  local stringLen = string.len(s)
232
  repeat
233
    local curChar = string.sub(s,endPos,endPos)
234
    -- Character escaping is only used to escape the string delimiters
235
    if not escaped then
236
      if curChar==[[\]] then
237
        escaped = true
238
      else
239
        bEnded = curChar==startChar
240
      end
241
    else
242
      -- If we're escaped, we accept the current character come what may
243
      escaped = false
244
    end
245
    endPos = endPos + 1
246
    base.assert(endPos <= stringLen+1, "String decoding failed: unterminated string at position " .. endPos)
247
  until bEnded
248
  local stringValue = 'return ' .. string.sub(s, startPos, endPos-1)
249
  local stringEval = base.loadstring(stringValue)
250
  base.assert(stringEval, 'Failed to load string [ ' .. stringValue .. '] in JSON4Lua.decode_scanString at position ' .. startPos .. ' : ' .. endPos)
251
  return stringEval(), endPos  
252
end
253
 
254
function decode_scanWhitespace(s,startPos)
255
  local whitespace=" \n\r\t"
256
  local stringLen = string.len(s)
257
  while ( string.find(whitespace, string.sub(s,startPos,startPos), 1, true)  and startPos <= stringLen) do
258
    startPos = startPos + 1
259
  end
260
  return startPos
261
end
262
 
263
function encodeString(s)
264
  s = string.gsub(s,'\\','\\\\')
265
  s = string.gsub(s,'"','\\"')
266
  s = string.gsub(s,'\n','\\n')
267
  s = string.gsub(s,'\t','\\t')
268
  return s
269
end
270
 
271
function isArray(t)
272
  -- Next we count all the elements, ensuring that any non-indexed elements are not-encodable
273
  -- (with the possible exception of 'n')
274
  local maxIndex = 0
275
  for k,v in base.pairs(t) do
276
    if (base.type(k)=='number' and math.floor(k)==k and 1<=k) then      -- k,v is an indexed pair
277
      if (not isEncodable(v)) then return false end     -- All array elements must be encodable
278
      maxIndex = math.max(maxIndex,k)
279
    else
280
      if (k=='n') then
281
        if v ~= table.getn(t) then return false end  -- False if n does not hold the number of elements
282
      else -- Else of (k=='n')
283
        if isEncodable(v) then return false end
284
      end  -- End of (k~='n')
285
    end -- End of k,v not an indexed pair
286
  end  -- End of loop across all pairs
287
  return true, maxIndex
288
end
289
 
290
function isEncodable(o)
291
  local t = base.type(o)
292
  return (t=='string' or t=='boolean' or t=='number' or t=='nil' or t=='table') or (t=='function' and o==null)
293
end
294
295
--------------------------------------------------------------------------------
296
--------------------------------------------------------------------------------
297
298
-- ComputerCraft IRC bot code begins here
299
300
--------------------------------------------------------------------------------
301
--------------------------------------------------------------------------------
302
local exeTime = 120
303
local defaultNick = "cc-turtle-bot"..tostring(math.random(1,1000))
304
local nick = defaultNick
305
local newNick = ""
306
307
local counter = 0 -- used by the qwebirc protocol for something
308
local sessionID = "" -- as is this, although a bit more self evident
309
310
local currentChannel = "#cctesting"
311
local quitReason = ""
312
313-
local actions = {
313+
314-
	["f"] = turtle.forward,
314+
315-
	["fd"] = turtle.forward,
315+
316-
	["forwards"] = turtle.forward,
316+
317-
	["b"] = turtle.back,
317+
318-
	["bk"] = turtle.back,
318+
        local result = "Everything went fine"
319-
	["u"] = turtle.up,
319+
320-
	["d"] = turtle.down,
320+
		local func,err = loadstring("return "..code)
321-
	["dn"] = turtle.down,
321+
                local succ
322-
	["down"] = turtle.down,
322+
                if not func then
323-
	["l"] = turtle.turnLeft,
323+
                     func,err = loadstring(code)
324-
	["lt"] = turtle.turnLeft,
324+
                end
325-
	["left"] = turtle.turnLeft,
325+
		if func then
326-
	["r"] = turtle.turnRight,
326+
                     succ,err = pcall(func)
327-
	["rt"] = turtle.turnRight,
327+
                end
328-
	["right"] = turtle.turnRight,
328+
		result = (succ and "Success: " or "Failed: ")..tostring(err)
329-
	["dg"] = turtle.dig,
329+
330-
	["dig"] = turtle.dig,
330+
331-
	["du"] = turtle.digUp,
331+
332-
	["dd"] = turtle.digDown,
332+
333-
	["da"] = function() return turtle.digUp() or turtle.dig() or turtle.digDown() end,
333+
334-
	["df"] = function() turtle.dig() return turtle.forward() end,
334+
335-
	["dgd"] = function() turtle.digDown() return turtle.down() end,
335+
336-
	["dgu"] = function() turtle.digUp() return turtle.up() end,
336+
337-
	["sn"] = function() turtle.select((turtle.getSelectedSlot()) % 16 + 1) return true end,
337+
338-
	["sp"] = function() turtle.select((turtle.getSelectedSlot() +14) % 16 + 1) return true end,
338+
339-
	["gic"] = function() return turtle.getItemCount(turtle.getSelectedSlot()) end,
339+
340-
	["gis"] = function() return turtle.getItemCount(turtle.getSelectedSlot()) end,
340+
341-
	["rfo"] = function() return turtle.refuel(1) end,
341+
342-
	["do"] = function() return turtle.drop(1) end,
342+
343-
	["ca"] = function() local r={} for i=1,16 do if turtle.compareTo(i) then table.insert(r,i) end end return r end,
343+
344-
	["tn"] = function() return turtle.transferTo((turtle.getSelectedSlot()) % 16 + 1) end,
344+
345-
	["ton"] = function() return turtle.transferTo((turtle.getSelectedSlot()) % 16 + 1,1) end,
345+
346-
	["c"] = turtle.craft,
346+
347-
	["cp"] = turtle.compare,
347+
348-
	["cpu"] = turtle.compareUp,
348+
349-
	["cpd"] = turtle.compareDown,
349+
350-
	["rf"] = turtle.refuel,
350+
351-
	["el"] = turtle.equipLeft,
351+
352-
	["er"] = turtle.equipRight,
352+
353-
	["a"] = turtle.attack,
353+
354-
	["au"] = turtle.attackUp,
354+
355-
	["ad"] = turtle.attackDown,
355+
356-
	["p"] = turtle.place,
356+
357-
	["pu"] = turtle.placeUp,
357+
358-
	["pd"] = turtle.placeDown,
358+
359-
	["dt"] = turtle.detect,
359+
360-
	["dtu"] = turtle.detectUp,
360+
361-
	["dtd"] = turtle.detectDown,
361+
362-
	["gfl"] = turtle.getFuelLevel,
362+
363-
	["gflm"] = turtle.getFuelLimit,
363+
364-
	["id"] = os.getComputerID,
364+
365-
	["label"] = os.getComputerLabel,
365+
366-
	["day"] = os.day,
366+
367-
	["time"] = os.time,
367+
368-
	["commands"] = function() local result = "Commands: " for i,j in pairs(actions) do result=result..i..", " end return result:sub(1,-3).." Put m infront (mf instead f) for not aborting. Put n infront for negated return value. Loops are \"wl detect forward end\" or \"for 3 up end\"." end
368+
369-
}
369+
370-
for i,j in pairs(turtle) do
370+
371-
	if i ~= "native" then
371+
372-
		actions[i] = j
372+
373
	return send("QUIT :"..reason)
374
end
375
376
-- lua default string methods suck :/
377
split = function(str,sep)
378
        local sep, fields = sep or ":", {}
379-
	local result = "Everything went fine"
379+
380
        str:gsub(pattern, function(c) fields[#fields+1] = c end)
381-
		local step = 1
381+
382-
		local inst = split(code, " ")
382+
383-
		local markers = {}
383+
384-
		local succ = true
384+
385-
		while step <= #inst and succ do
385+
386-
			local optio = inst[step]:sub(1,1) == "m"
386+
387-
			local negat = inst[step]:sub(1,1) == "n"
387+
388-
			local cmd = (optio or negat) and inst[step]:sub(2) or inst[step]
388+
389-
			if actions[cmd] then
389+
390-
				succ,result = actions[cmd]()
390+
391-
				succ = optio or (type(succ) =="boolean" and succ ~= negat) or (type(succ) ~="boolean" and succ)
391+
392-
			elseif cmd:sub(1,1) == "s" and tonumber(cmd:sub(2) or "a") then
392+
393-
				turtle.select(tonumber(cmd:sub(2)))
393+
394-
			elseif cmd == "wl" and step < #inst then
394+
395-
				if not markers[1] or markers[1][1] ~= step then
395+
396-
					table.insert(markers,1,{step})
396+
397
	end
398-
				local negat = inst[step+1]:sub(1,1) == "n"
398+
399-
				local concmd = negat and inst[step+1]:sub(2) or inst[step+1]
399+
400-
				if not actions[concmd] then
400+
401-
					succ, result = false,"Unknown Command:"..inst[step+1]
401+
402-
				else
402+
403-
					local cond = actions[concmd]()
403+
404-
					if (type(cond) == "boolean" and cond ~= negat) or (type(cond) == "number" and ((cond >0) ~= negat)) then
404+
405-
						step = step + 1
405+
406-
					else
406+
407-
						while step <= #inst and inst[step] ~= "end" do step = step +1 end
407+
408-
						table.remove(markers,1)
408+
409
			local channel = data[i][4][1]:lower()
410
			local msg = data[i][4][2]
411-
			elseif cmd == "for" and step < #inst then
411+
412-
				if not markers[1] or markers[1][1] ~= step then
412+
413-
					table.insert(markers,1,{step,tonumber(inst[step+1]) or 1})
413+
414
				send("JOIN "..currentChannel)
415-
				markers[1][2] = markers[1][2]-1
415+
416-
				step = step + 1
416+
417-
			elseif cmd == "end" and #markers > 0 then
417+
418-
				sleep(0)
418+
419-
				if inst[markers[1][1]] ~= "for" or markers[1][2] >0 then
419+
				shell.run("pastebin get 4KnCPupW .ircbot2")
420-
					step = markers[1][1]-1
420+
421-
				else
421+
422-
					table.remove(markers,1)
422+
423
					end
424-
			elseif cmd == "send" then
424+
425-
				send("PRIVMSG "..currentChannel.." :"..writeResult({succ,result},""))
425+
426-
			else 
426+
427-
				succ, result = false,"Unknown Command:"..cmd
427+
			else
428
				local r = runCode(msg)
429-
			step = step + 1
429+
430
			end
431-
		result = (succ == true) and "Success" or (succ == false) and {"Failed",result,"On "..tostring(step-1)..". Operation"} or {succ,result}
431+
432-
		result = writeResult(result,"")
432+
433
			send("JOIN "..currentChannel)
434
		end
435
	end
436
end
437
438
local receive = function()
439
	local resp = connect()
440
	if not resp then print(os.version()) return end
441
	local _data = resp.readAll()
442
	local data = decode(_data)
443
	sessionID = data[2]
444
	resp = recv()
445
	while resp do
446
		_data = resp.readAll()
447
		if #_data > 0 then
448
			data = decode(_data)
449
			handleResponse(data)
450
		end
451
		resp = recv()
452
	end
453
	quitReason = "Disconnected!"
454
end
455
456
457
term.clear()
458
term.setCursorPos(1,1)
459
receive()