View difference between Paste ID: w906q6ti and X8NEcEVy
SHOW: | | - or go back to the newest paste.
1
--# Turtle Extended API v0.4
2
--# Made By Wojbie
3
--# http://pastebin.com/X8NEcEVy
4
5
6
--Rebuild and restructure!
7
--split internal and front functions
8
--Separate functions into subtables.
9
--API Settings -  TagControl,DaemonControl
10
--Utility ? --making a point ect?
11
12
--work on naming convention
13
--cram similiar function into one with some flags.
14
--add some kind of map system. - auto save contents of inspection. (Deamon idea? Scan all turtle sees ever so often?)
15
--add onScan function()
16
17
--defininf variables for whole api
18
19
--investigame turtle.inventory event for daemon
20
21
--crafting database? use tags for types of wood ect.
22
23
24
25
26
27
--##     ERROR TESTS     ##--
28
29
if shell or multishell then
30
	print("You have run this api instead of loading it. There is no point in doing that. Use os.loadApi to load it.")
31
	return
32
end
33
34
if not turtle then
35
	error("This is not a turtle. This api will not work outside of the turtle.")
36
end
37
38
--##     CONSTANTS     ##--
39
40
local oldturtle = turtle --Pointing local at global turtle (in case user overwrites it with this api)
41
nativeTurtle=oldturtle --acces to basic turtle (in case user overwrites it with this api)
42
versionName="TurtleExtended By Wojbie"
43
versionNumber=0.4
44
45
--##     GLOBALS     ##--
46
47
local bMovelock = true --Is true if position of turtle is not set. Stops all movement functions. They will return false.
48
local bScanner = false --Automatic scanning to map on movement? Slows movement down.
49
local bBrutal = false --Automatic attacking if movement falls
50
local bVacuum = false --Automatic vacuum as it moves around
51
local pos
52
53
local bInMove = false
54
55
56
57
--##     SUBTABLES     ##--
58
59
util = {}
60
tags = {}
61
map = {}
62
63
64
--##     RANDOM USEFULL FUCTIONS     ##--
65
66
local function save(A,B) local file = fs.open(tostring(A),"w") file.write(B) file.close() end
67
local function saveT(A,B) save(A,textutils.serialize(B)) end
68
local function saveTL(A,B) save(A,string.gsub(textutils.serialize(B),"\n%s*","")) end
69
70
local function get(A) local file = fs.open(tostring(A),"r") if not file then return false end local data = file.readAll() file.close() if data then return data end end
71
local function getT(A) local data = get(A) if data then data = textutils.unserialize(data) end if data then return data end end
72
local function getHttp(A) if not http.checkURL(A) then return false end local file = http.get(A) if not file then return false end local data = file.readAll() file.close() if data then return data end end
73
74
local function copyT(...) --Copy table - if more than one merge them - in case of overwriting values last one gets its way
75
tArgs={...}
76
local B={}
77
	for _,A in pairs(tArgs) do
78
		if A and type(A)=="table" then
79
			for i,k in pairs(A) do
80
				if type(k)=="table" then B[i]=copyT( B[i] or {},k) 
81
				else B[i]=k end
82
			end
83
		end
84
	end
85
return B
86
end
87
88
89
--##     TAG DATABASE     ##--
90
	
91
local ProtectedTags={["#All"]=true}
92
93
local tagList={ --#Modname tag is always added by dynamic code 
94
["#bedrock"]={{"minecraft:bedrock"},{"factorization:FracturedBedrock"},},
95
["#stone"]={{"minecraft:stone"},},
96
["#cobble"]={{"minecraft:cobblestone"},},
97
["#dirt"]={{"minecraft:dirt",0},{"minecraft:grass"}},
98
["#podzol"]={{"minecraft:dirt",2}},
99
100
["#sand"]={{"minecraft:sand"},},
101
["#gravel"]={{"minecraft:gravel"},},
102
103
["#log"]={{"minecraft:log"},{"minecraft:log2"}},
104
["#leaves"]={{"minecraft:leaves"},{"minecraft:leaves2"}},
105
["#tree"]={"#log","#leaves"},
106
["#sapling"]={{"minecraft:sapling"}},
107
108
["#gravity"]={"#sand","#gravel"},
109
110
["#liquid"]={{"minecraft:flowing_lava"},{"minecraft:lava"},{"minecraft:flowing_water"},{"minecraft:water"}},
111
["#liquidSourceBlock"]={{"minecraft:flowing_lava",0},{"minecraft:lava",0},{"minecraft:flowing_water",0},{"minecraft:water",0}}, --Thanks to Bomb Bloke for helping me test that!
112
113
["#containder"]={{"minecraft:chest"},},
114
115
["#unique"]={{"minecraft:dragon_egg"}},
116
117
["#ground"]={"#dirt","#stone"},
118
119
["#ore"]={"#vanillaOre"},
120
["#mineableOre"]={"#vanillaOre"},
121
["#vanillaOre"]={{"minecraft:gold_ore"},{"minecraft:iron_ore"},{"minecraft:coal_ore"},{"minecraft:lapis_ore"},{"minecraft:diamond_ore"},{"minecraft:redstone_ore"},{"minecraft:emerald_ore"},{"minecraft:quartz_ore"}},
122
123
--["#sample"]={{"minecraft:stone"},{"minecraft:lava",1},"#stone"},
124
125
126
--Blacklist tags
127
["#DigBlacklist"]={"#Blacklist",{"minecraft:mob_spawner"},"#ComputerCraft:","#computercraft:"}, --Spawners are to preacius to mine, Also no canibalism.
128
["#DigWhitelist"]={"#Whitelist",},
129
["#PlaceBlacklist"]={"#Blacklist",{"minecraft:bedrock"}}, --No placing Bedrock on my watch
130
["#PlaceWhitelist"]={"#Whitelist",},
131
["#Blacklist"]={},
132
["#Whitelist"]={},
133
134
--Test tags
135
["#TestAll"]={"#All"},
136
["#TestComputertag"]={"#ComputerCraft:","#computercraft:"},
137
}
138
139
local lookupName={}
140
141
--[[{
142
["minecraft:stone"]=
143
	{
144
	[true]={["#stone"]=true},
145
	[3]={["#stone3"]=true},
146
	[m3]={["#stonem3"]=true},
147
	[d3]={["#stoned3"]=true},
148
	}
149
}]]--
150
151
local lookupTag={}
152
153
--[[{
154
["#stone"]=
155
	{
156
	["ground"]=true,
157
	}
158
}]]--
159
160
--Database operations
161
162
local function assigntag(tag,list)
163
	for _,v in pairs(list) do	
164
		if type(v)=="table" then --name meta or just name combo
165
			if not v[2] then v[2] = true end
166
			if not lookupName[v[1]] then lookupName[v[1]]={} end
167
			if not lookupName[v[1]][v[2]] then lookupName[v[1]][v[2]]={} end
168
			lookupName[v[1]][v[2]][tag]=true
169
		elseif type(v)=="string" then --tag
170
			if not lookupTag[v] then lookupTag[v]={} end
171
			lookupTag[v][tag]=true
172
		end
173
	end
174
end
175
176
local function removetag(tag,list)
177
	for _,v in pairs(list) do	
178
		if type(v)=="table" then --name meta or just name combo
179
			if not v[2] then v[2] = true end
180
			if not lookupName[v[1]] then lookupName[v[1]]={} end
181
			if not lookupName[v[1]][v[2]] then lookupName[v[1]][v[2]]={} end
182
			lookupName[v[1]][v[2]][tag]=nil
183
		elseif type(v)=="string" then --tag
184
			if not lookupTag[v] then lookupTag[v]={} end
185
			lookupTag[v][tag]=nil
186
		end
187
	end
188
end
189
190
--Filling the database
191
192
for i,k in pairs(tagList) do
193
	assigntag(i,k)
194
end
195
196
--User Accesable functions
197
198
tags.createTag = function(Tag) --Creates new tag
199
	if tagList[Tag] then return false,"Tag Exists" end
200
	if ProtectedTags[Tag] then return false,"Tag Protected" end
201
	tagList[Tag]={}
202
	return true
203
end
204
local createTag = tags.createTag
205
206
tags.deleteTag = function(Tag) --Deletes tag and all stuff regeristered to it.
207
	if not tagList[Tag] then return false,"No such Tag" end
208
	if ProtectedTags[Tag] then return false,"Tag Protected" end
209
	removetag(Tag,tagList[Tag])
210
	tagList[Tag]=nil
211
	return true
212
end
213
214
tags.isTag = function(Tag) --cheacks is tag exists
215
	return tagList[Tag] and true or false
216
end
217
local isTag = tags.isTag
218
219
tags.addBlockToTag = function(Tag,Block,Meta)
220
	if not tagList[Tag] then return false,"No such Tag" end
221
	if ProtectedTags[Tag] then return false,"Tag Protected" end
222
	if lookupName[Block] and lookupName[Block][Meta or true] and lookupName[Block][Meta or true][Tag] then return true end
223
	if not tagList[Tag] then tagList[Tag] = {} end
224
	table.insert(tagList[Tag],{Block,Meta or true})
225
	assigntag(Tag,tagList[Tag]) --update lookup tables
226
	return true
227
end
228
229
tags.addSubTagToTag = function(Tag,Child)
230
	if not tagList[Tag] then return false,"No such Tag" end
231
	if ProtectedTags[Tag] then return false,"Tag Protected" end
232
	if not tagList[Tag] then tagList[Tag] = {} end
233
	if lookupTag[Child] and lookupTag[Child][Tag] then  return true end
234
	table.insert(tagList[Tag],Child)
235
	assigntag(Tag,tagList[Tag]) --update lookup tables
236
	return true
237
end
238
239
tags.listTag = function(Tag)
240
	if not tagList[Tag] then return false,"No such Tag" end
241
	if ProtectedTags[Tag] then return false,"Tag Protected" end
242
	return copyT(tagList[Tag])
243
end
244
245
tags.removeItemFromTag = function(Tag,num)
246
	if not tagList[Tag] then return false,"No such Tag" end
247
	if ProtectedTags[Tag] then return false,"Tag Protected" end
248
	removetag(Tag,tagList[Tag])
249
	table.remove(tagList[Tag],num)
250
	assigntag(Tag,tagList[Tag])
251
	return true
252
end
253
254
tags.saveTags = function(A)
255
	saveT(A or "/tag.log",tagList)
256
end
257
258
tags.loadTags = function(A)
259
	tagList=getT(A or"/tag.log") or {}
260
	lookupName={}
261
	lookupTag={}
262
	for i,k in pairs(tagList) do
263
		assigntag(i,k)
264
	end
265
end
266
267
tags.loadTagPatch = function(A) --
268
	patch=getT(A) or {}
269
	for i,k in pairs(patch) do
270
		if not isTag(i) then createTag(i) end --if tag don't exists then create it.
271
		for j,m in pairs(k) do
272
			table.insert(tagList[i],m) --add new data to tag table
273
		end
274
		assigntag(i,k) --populate lookup tables with patch data
275
	end
276
end
277
278
--##     MAP DATABASE     ##--
279
280
local internamMap = {} 
281
local metay = {__index=function(f,k) f[k] = {} return f[k] end}--if no y make y and return it (placed on y table)
282
local metax = {__index=function(f,k) f[k] = setmetatable({},metay) return f[k] end} --if no x make x and return it (placed on map table)
283
setmetatable(internamMap,metax)
284
285
local function cleanMap() --looks trought the map and removes not valid values and empty tables. Cause its eather air or unknown and we don't care about both.
286
	for kx,vx in pairs(internamMap) do
287
		for ky,vy in pairs(vx) do
288
			for kz,vz in pairs(vy) do
289
				if type(vz)~="table" or (type(vz)=="table" and not next(vz)) then vy[kz]=nil end
290
			end
291
			if not next(vy) then vx[ky]=nil end
292
		end
293
		if not next(vx) then internamMap[kx]=nil end
294
	end
295
end
296
297
local function setBlock(block,x,y,z) if type(block)=="table" then internamMap[x][y][z] = block return true end end
298
local function getBlock(x,y,z) return internamMap[x][y][z] end --add tags in this return
299
local function saveMap() end
300
local function loadMap() end
301
302
map.setBlock = setBlock
303
map.getBlock = getBlock
304
map.saveMap = saveMap
305
map.loadMap = loadMap
306
307
util.setAutoScan = function(A) bScanner = A and true end 
308
util.getAutoScan = function() return bScanner and true end 
309
310
311
--##     POINT METAMAGIC     ##--
312
313
local metaPoint
314
metaPoint = {
315
__index = {
316
317
copy= function(t) return setmetatable({x=t.x,y=t.y,z=t.z,xd=t.xd,zd=t.zd},metaPoint)  end,
318
319
offset = function(t,ox,oy,oz) return t.x and t.y and t.z and setmetatable({x=t.x+ox,y=t.y+oy,z=t.z+oz,xd=t.xd,zd=t.zd},metaPoint)  end,
320
offsetL = function(t,ox,oy,oz) return t.x and t.y and t.z and t.xd and t.zd and setmetatable({x=t.x+ox*t.xd+oz*-t.zd,y=t.y+oy,z=t.z+oz*t.xd+ox*t.zd,xd=t.xd,zd=t.zd},metaPoint) end,
321
offsetP = function(t,A) return t.offset and t:offset(A.x,A.y,A.z) end,
322
offsetPL = function(t,A) return t.offsetL and t:offsetL(A.x,A.y,A.z) end, --local to provided point
323
324
ox = function(t,A) return t.offset and t:offset(A or 0,0,0) end,
325
oy = function(t,A) return t.offset and t:offset(0,A or 0,0) end,
326
oz = function(t,A) return t.offset and t:offset(0,0,A or 0) end,
327
328
up = function(t,A) return t.offset and t:offset(0,(A or 1),0) end,
329
down = function(t,A) return t.offset and t:offset(0,-(A or 1),0) end,
330
331
forward = function(t,A) return t.offset and t.xd and t.zd and t:offset((A or 1)*t.xd,0,(A or 1)*t.zd) end,
332
back = function(t,A) return t.offset and t.xd and t.zd and t:offset(-(A or 1)*t.xd,0,-(A or 1)*t.zd) end,
333
334
left = function(t,A) return t.offset and t.xd and t.zd and t:offset((A or 1)*t.zd,0,(A or 1)*-t.xd) end,
335
right = function(t,A) return t.offset and t.xd and t.zd and t:offset((A or 1)*-t.zd,0,(A or 1)*t.xd) end,
336
337
turnLeft = function(t) return t.offset and t.xd and t.zd and t:offset(0,0,0):setxd(t.zd):setzd(-t.xd) end,
338
turnRight = function(t) return t.offset and t.xd and t.zd and t:offset(0,0,0):setxd(-t.zd):setzd(t.xd) end,
339
turnBack = function(t) return t.offset and t.xd and t.zd and t:offset(0,0,0):setxd(-t.xd):setzd(-t.zd) end,
340
341
upG = function(t,A) return t.offset and t:offset(0,(A or 1),0) end,
342
downG = function(t,A) return t.offset and t:offset(0,-(A or 1),0) end,
343
344
forwardG = function(t,A) return t.offset and pos.xd and pos.zd and t:offset((A or 1)*pos.xd,0,(A or 1)*pos.zd) end,
345
backG = function(t,A) return t.offset and pos.xd and pos.zd and t:offset(-(A or 1)*pos.xd,0,-(A or 1)*pos.zd) end,
346
347
leftG = function(t,A) return t.offset and pos.xd and pos.zd and t:offset((A or 1)*pos.zd,0,(A or 1)*-pos.xd) end,
348
rightG = function(t,A) return t.offset and pos.xd and pos.zd and t:offset((A or 1)*-pos.zd,0,(A or 1)*pos.xd) end,
349
350
block = function(t) return t.x and t.y and t.z and getBlock(t.x,t.y,t.z) end,
351
unp = function(t) return t.x,t.y,t.z,t.xd,t.zd end,
352
353
getf = function(t) if t.xd==0 and t.zd==1 then return 0
354
		elseif t.xd==-1 and t.zd==0 then return 1
355
		elseif t.xd==0 and t.zd==-1 then return 2
356
		elseif t.xd==1 and t.zd==0 then return 3 end end,
357
		
358
setf = function(t,A) if A==0 then t.xd=0 t.zd=1 return t
359
		elseif A==1 then t.xd=-1 t.zd=0 return t
360
		elseif A==2 then t.xd=0 t.zd=-1 return t
361
		elseif A==3 then t.xd=1 t.zd=0 return t end end,
362
		
363
setx = function(t,A) t.x=A return t end,
364
sety = function(t,A) t.y=A return t end,
365
setz = function(t,A) t.z=A return t end,
366
367
setxd = function(t,A) t.xd=A return t end,
368
setzd = function(t,A) t.zd=A return t end,
369
370
clearf = function(t,A) t.zd=nil t.xd=nil return t end,
371
372
tos = function(t) return tostring(t) end,
373
},
374
--__newindex
375
--__add
376
--__sub
377
--__mul
378
--__div
379
--__mod
380
--__pow
381
--__unm (-A)
382
--__concat
383
384
--__len = Distance for current point to that point in shortest way possible
385
--__eq  equal = compare coordinates and directions if they are there. 
386
--__lt  larger,smaller -->  compare fuel cost on direct route from current pos
387
--__le - defaults to not lt so its cool
388
389
--__call
390
391
__tostring = function(t) return "["..(t.x and " x:"..t.x or "")..(t.y and " y:"..t.y or "")..(t.z and " z:"..t.z or "")..(t.xd and " xd:"..t.xd or "")..(t.zd and " zd:"..t.zd or "")..(t.getf and t:getf() and " f:"..t:getf() or "").." ]" end,
392
--__metatable
393
394
--# 5.2 up
395
--__ipairs
396
--__pairs
397
398
--5.3 is ignored for now. lot of bitwise meta added.
399
}
400
401
--##DEBUG ITEM
402
testpoint = setmetatable({x=0,y=0,z=0,xd=0,zd=1},metaPoint)
403
404
util.makePoint = function(x,y,z,xd,zd) --make a point from coordinates
405
	return setmetatable({["x"]=x,["y"]=y,["z"]=z,["xd"]=xd,["zd"]=zd},metaPoint)
406
end
407
408
util.remakePoint = function(A) --make a point from table
409
	return setmetatable(A,metaPoint)
410
end
411
412
util.savePoint = function(A,B) --save point a into file b
413
	saveT(B,A)
414
end
415
metaPoint.__index.save = util.savePoint --add it to point metatable as save
416
417
util.loadPoint = function(A)
418
	return setmetatable(getT(A or"/gps.log"),metaPoint)
419
end
420
421
422
423
--##     LOCAL POSITION     ##--
424
425
pos = setmetatable({x=0,y=0,z=0,xd=1,zd=0},metaPoint) --position of turtle
426
427
--[[savePos = function(A)
428
	saveT(A or "/gps.log",pos)
429
end
430
431
loadPos = function(A)
432
	pos=setmetatable(getT(A or"/gps.log"),metaPoint) or pos
433
end]] --allows bad coding practise. If you realy need it the uncomment it.
434
435
setPos = function(x,y,z,xd,zd) --set position to provided parameters
436
  pos=setmetatable({["x"]=x,["y"]=y,["z"]=z,["xd"]=xd,["zd"]=zd},metaPoint)
437
  bMovelock = false
438
end
439
440
getPos = function() --get static table with current position
441
 return setmetatable(copyT(pos),metaPoint)
442
end
443
444
--##SEMI-DEBUG ITEM
445
getPosDynamic = function() --get table that always contains current position
446
 return setmetatable({},{__index=pos,__newindex=function() end,__tostring=metaPoint.__tostring})
447
end
448
449
--##     MOVEMENT CONTROLS     ##--
450
451
--##INTERNAL
452
453
local function scan() --scans up forward down
454
	local status,response,block
455
	status,response = oldturtle.inspectUp()
456
	if status then
457
		block = pos:up():clearf()
458
		setBlock(response,block:unp())
459
	end
460
	status,response = oldturtle.inspect()
461
	if status then
462
		block = pos:forward():clearf()
463
		setBlock(response,block:unp())
464
	end
465
	status,response = oldturtle.inspectDown()
466
	if status then
467
		block = pos:down():clearf()
468
		setBlock(response,block:unp())
469
	end
470
end
471
472
local function scanf() --scans just forward
473
	local status,response,block
474
	status,response = oldturtle.inspect()
475
	if status then
476
		block = pos:forward():clearf()
477
		setBlock(response,block:unp())
478
	end
479
end
480
481
local function vacuum()
482
	while turtle.suckUp() do end
483
	while turtle.suck() do  end
484
	while turtle.suckDown() do end
485
end
486
487
turnRight = function(A)
488
		if bMovelock then return false,"Unknown Position, movement locked" end
489
		oldturtle.turnRight()
490
		pos.xd, pos.zd = -pos.zd, pos.xd
491
		if bScanner or A then scanf() end
492
		if  bVacuum then vacuum() end
493
		return true
494
end
495
 
496
497
turnLeft = function(A)
498
		if bMovelock then return false,"Unknown Position, movement locked" end
499
		oldturtle.turnLeft()
500
		pos.xd, pos.zd = pos.zd, -pos.xd
501
		if  bScanner or A then scanf() end
502
		if  bVacuum then vacuum() end
503
		return true
504
end
505
506
507
up = function(A)
508
	bInMove = true
509
	if bMovelock then bInMove = false return false,"Unknown Position, movement locked" 
510
	elseif oldturtle.up() or (bBrutal and oldturtle.attack() and oldturtle.up()) then
511
		pos.y = pos.y+1
512
		bInMove = false 
513
		if  bScanner or A then scan() end
514
		if  bVacuum then vacuum() end
515
		return true
516
	else
517
		bInMove = false 
518
		return false
519
	end
520
end
521
522
523
down = function(A)
524
	bInMove = true
525
	if bMovelock then bInMove = false  return false,"Unknown Position, movement locked" 
526
	elseif oldturtle.down() or (bBrutal and oldturtle.attackDown() and oldturtle.down())then
527
		pos.y = pos.y-1
528
		bInMove = false 
529
		if  bScanner or A then scan() end
530
		if  bVacuum then vacuum() end
531
		return true
532
	else
533
		bInMove = false 
534
		return false
535
	end
536
end
537
 
538
539
forward = function(A)
540
	bInMove = true
541
	if bMovelock then bInMove = false return false,"Unknown Position, movement locked" 
542
	elseif oldturtle.forward() or (bBrutal and oldturtle.attack() and oldturtle.forward()) then
543
		pos.x = pos.x+pos.xd
544
		pos.z = pos.z+pos.zd
545
		bInMove = false
546
		if  bScanner or A then scan() end
547
		if  bVacuum then vacuum() end
548
		return true
549
	else
550
		bInMove = false
551
		return false
552
	end
553
end
554
 
555
back = function(A)
556
	bInMove = true
557
	if bMovelock then bInMove = false return false,"Unknown Position, movement locked" 
558
	elseif oldturtle.back() then
559
		pos.x = pos.x-pos.xd
560
		pos.z = pos.z-pos.zd
561
		bInMove = false
562
		if  bScanner or A then scan() end
563
		if  bVacuum then vacuum() end
564
		return true
565
	else
566
		bInMove = false
567
		return false
568
	end
569
end
570
571
572
util.setBrutal = function(A) bBrutal = A and true end 
573
util.getBrutal = function() return bBrutal and true end 
574
util.setVacuum = function(A) bVacuum = A and true end 
575
util.getVacuum = function() return bVacuum and true end 
576
util.getBrake = function() return bMovelock and true end 
577
578
579
--##     GPS LOCATING     ##--
580
581
gpsPos=function(A,B) --gets pos from GPS will get lost in process sometimes. -- add movement up and down.
582
	local pos1,pos2={},{}
583
	
584
	if B then pos1={gps.locate(2,A)} if pos1 then setPos(pos1[1],pos1[2],pos1[3],1,0) bMovelock = true return true end end
585
586
	if getFuelLevel()<2 then return false,"Fuel Level Insufficient" end
587
	pos1={gps.locate(2,A)}
588
	if not pos1[1] then return false,"No GPS Signal" end
589
	
590
	if pos1[1] and oldturtle.forward() then
591
		pos2={gps.locate(2,A)}
592
		if pos2[1] then
593
			setPos(pos2[1],pos2[2],pos2[3],pos2[1]-pos1[1],pos2[3]-pos1[3])
594
			back()
595
			return true
596
		else
597
			oldturtle.back()
598
			return false,"GPS Signal Error"
599
		end
600
	elseif pos1[1] and oldturtle.back() then
601
		pos2={gps.locate(2,A)}
602
		if pos2[1] then
603
			setPos(pos2[1],pos2[2],pos2[3],pos1[1]-pos2[1],pos1[3]-pos2[3])
604
			forward()
605
			return true
606
		else
607
			oldturtle.forward()
608
			return false,"GPS Signal Error"
609
		end
610
	end
611
	
612
	oldturtle.turnLeft()
613
	
614
	if pos1[1] and oldturtle.forward() then
615
		pos2={gps.locate(2,A)}
616
		if pos2[1] then
617
			setPos(pos2[1],pos2[2],pos2[3],pos2[1]-pos1[1],pos2[3]-pos1[3])
618
			back()
619
			turnRight()
620
			return true
621
		else
622
			oldturtle.back()
623
			return false,"GPS Signal Error"
624
		end
625
	elseif pos1[1] and oldturtle.back() then
626
		pos2={gps.locate(2,A)}
627
		if pos2[1] then
628
			setPos(pos2[1],pos2[2],pos2[3],pos1[1]-pos2[1],pos1[3]-pos2[3])
629
			forward()
630
			turnRight()
631
			return true
632
		else
633
			oldturtle.forward()
634
			return false,"GPS Signal Error"
635
		end
636
	end
637
	
638
	oldturtle.turnRight()
639
	
640
	return false,"Can't move to confirm position"
641
end
642
643
--##     INSPECT AND GETDETAIL     ##--
644
645
local function addtags(t,bDam) 
646
	local tags={}
647
	local Worklist = copyT(lookupName[t.name] and lookupName[t.name][true],lookupName[t.name] and lookupName[t.name][t.metadata or t.damage],lookupName[t.name] and lookupName[t.name][bDam and "d"..t.damage or "m"..t.metadata]) --merge tags from main block and from metadata/damage subblock and from metadata,damage blocks depending on mode
648
	local Modtag="#"..string.match(t.name, "^([^:]+:)") --"^([^:]+):"
649
	Worklist[Modtag]=true
650
	Worklist["#All"]=true --Utility tag. 
651
	local empty=false
652
	
653
	while not empty do
654
		empty=true
655
		for i in pairs(copyT(Worklist)) do --for each tag analize
656
			empty=false
657
			Worklist[i]=nil
658
			tags[i]=true
659
			Worklist=copyT(Worklist,lookupTag[i]) --add parent tags to WorkList
660
		end
661
	end
662
	
663
	t.tags=tags
664
	return t
665
end
666
667
inspect = function()
668
	local status,response = oldturtle.inspect()
669
	if status then
670
		if not bMovelock then 
671
			local block = pos:forward():clearf()
672
			setBlock(response,block:unp())
673
			response.point=block
674
		end
675
		return status,addtags(response) --scan for m3 type tags -- boollean left as nil
676
	else
677
		return status,response
678
	end
679
end
680
681
inspectUp = function()
682
	local status,response = oldturtle.inspectUp()
683
	if status then
684
		if not bMovelock then 
685
			local block = pos:up():clearf()
686
			setBlock(response,block:unp())
687
			response.point=block
688
		end
689
		return status,addtags(response) --scan for m3 type tags -- boollean left as nil
690
	else
691
		return status,response
692
	end
693
end
694
695
inspectDown = function()
696
	local status,response = oldturtle.inspectDown()
697
	if status then
698
		if not bMovelock then 
699
			local block = pos:down():clearf()
700
			setBlock(response,block:unp())
701
			response.point=block:clearf()
702
		end
703
		return status,addtags(response) --scan for m3 type tags -- boollean left as nil
704
	else
705
		return status,response
706
	end
707
end
708
709
getItemDetail = function(A)
710
local response = oldturtle.getItemDetail(A)
711
	if response then
712
		return addtags(response,true) --scan for d3 type tags
713
	else
714
		return response
715
	end
716
end
717
718
--##     COMPARE EXPANSION     ##--
719
720
local function comp(A,B)
721
	if A and type(A)=="number" and A>=1 and A<=16 then
722
		local C=oldturtle.getSelectedSlot()
723
		oldturtle.select(A)
724
		local D=B()
725
		oldturtle.select(C)
726
		return D
727
	else
728
		return B()
729
	end
730
end	
731
732
compareSlot = function(A) return comp(A,oldturtle,compare) end
733
compareSlotUp = function(A) return comp(A,oldturtle,compareUp) end
734
compareSlotDown = function(A) return comp(A,oldturtle,compareDown) end
735
736
compareTwo = function(A,B)
737
	local C=oldturtle.getSelectedSlot()
738
	oldturtle.select(A)
739
	local D=oldturtle,compareTo(B)
740
	oldturtle.select(C)
741
	return D
742
end
743
744
--##     FUEL INFORMATION     ##--
745
746
local Fuellimit=term.native().isColor() and 100000 or 20000
747
748
getFuelLevel = function()
749
	local temp=oldturtle.getFuelLevel()
750
	return temp=="unlimited" and Fuellimit or temp
751
end
752
753
getFuelLimit =  function()
754
	local temp=oldturtle.getFuelLimit()
755
	return temp=="unlimited" and Fuellimit or temp
756
end
757
758
getFuelPercent = function()
759
	return getFuelLevel()/getFuelLimit()
760
end
761
762
getFuelSpace = function()
763
	return getFuelLimit()-getFuelLevel()
764
end
765
766
--##     SMART REFUEL     ##--
767
768
refuel = function(A) --limit aware refuel
769
	A = A or 1000
770
	if A==0 or not oldturtle.refuel(0) then return oldturtle.refuel(0) end
771
	local current=getFuelLevel()
772
	local value=0
773
	if getFuelPercent()<1 then
774
		oldturtle.refuel(1)
775
		A=A-1
776
		value=getFuelLevel()-current
777
		local toRefuel=math.min(A,math.max(math.ceil(getFuelSpace()/value),0),oldturtle.getItemCount()) --64)
778
		if toRefuel > 0 then oldturtle.refuel(toRefuel) end
779
	end
780
	return true
781
end
782
783
--##     DIG AND PLACE BLACKLIST/WHITELIST     ##--
784
785
------------------------------------------------------------ADD	bScanner block,t = A() setBlock(t.point:unp(),nil)
786
787
local function di(A,B) 
788
	local block,t = A() 
789
	if block then
790
		--scan for whitelist tag
791
		if t.tags and t.tags["#DigWhitelist"] then return B() end
792
		--scan blacklist
793
		if t.tags and t.tags["#DigBlacklist"] then return false,"Blacklisted" end
794
		--do it normally
795
		return B()
796
	else
797
	return false,"Nothing to dig here"
798
	end
799
end
800
801
dig = function() return di(inspect,oldturtle.dig) end
802
digUp = function() return di(inspectUp,oldturtle.digUp) end
803
digDown = function() return di(inspectDown,oldturtle.digDown) end
804
805
------------------------------------------------------------ADD	bScanner block,t = A() setBlock(t.point:unp(),nil)
806
807
local function pi(A,B) 
808
	local t = getItemDetail() 
809
	if t then
810
		--scan for whitelist tag
811
		if t.tags and t.tags["#PlaceWhitelist"] then return A(B) end
812
		--scan blacklist
813
		if t.tags and t.tags["#PlaceBlacklist"] then return false,"Blacklisted" end
814
		--do it normally
815
		return A(B)
816
	else
817
	return false,"No items to place"
818
	end
819
end
820
821
place = function(A) return pi(oldturtle.place,A) end
822
placeUp = function() return pi(oldturtle.placeUp) end
823
placeDown = function() return pi(oldturtle.placeDown) end
824
825
--##     PATHFINGING     ##--
826
827
--Mode 3/4
828
829
local function upP(A,B,C) --A-Size, B-Scanning, C-Dig
830
	
831
	for i=1,A do
832
	
833
		if up(B) or (C and digUp() and up(B)) then
834
			return true
835
		else
836
		
837
			if math.random(0,1)==1 then
838
				if forward(B) or (C and dig() and forward(B)) or turnLeft(B) and turnLeft(B) and (forward(B) or (C and dig() and forward(B))) then if up(B) or (C and digUp() and up(B)) then return true end end
839
			else
840
				if turnLeft(B) and turnLeft(B) and (forward(B) or (C and dig() and forward(B))) or turnLeft(B) and turnLeft(B) and (forward(B) or (C and dig() and forward(B))) then if up(B) or (C and digUp() and up(B)) then return true end end
841
			end
842
			
843
			turnLeft(B)
844
			
845
			if math.random(0,1)==1 then
846
				if forward(B) or (C and dig() and forward(B)) or turnLeft(B) and turnLeft(B) and (forward(B) or (C and dig() and forward(B))) then if up(B) or (C and digUp() and up(B)) then return true end end
847
			else
848
				if turnLeft(B) and turnLeft(B) and (forward(B) or (C and dig() and forward(B))) or turnLeft(B) and turnLeft(B) and (forward(B) or (C and dig() and forward(B))) then if up(B) or (C and digUp() and up(B)) then return true end end
849
			end
850
			
851
		end
852
	end
853
	
854
	return false
855
end
856
857
local function downP(A,B,C)
858
859
	for i=1,A do
860
	
861
		if down(B) or (C and digDown() and down(B)) then
862
			return true
863
		else
864
		
865
			if math.random(0,1)==1 then
866
				if forward(B) or (C and dig() and forward(B)) or turnLeft(B) and turnLeft(B) and (forward(B) or (C and dig() and forward(B))) then if down(B) or (C and digDown() and down(B)) then return true end end
867
			else
868
				if turnLeft(B) and turnLeft(B) and (forward(B) or (C and dig() and forward(B))) or turnLeft(B) and turnLeft(B) and (forward(B) or (C and dig() and forward(B))) then if down(B) or (C and digDown() and down(B)) then return true end end
869
			end
870
			
871
			turnLeft(B)
872
			
873
			if math.random(0,1)==1 then
874
				if forward(B) or (C and dig() and forward(B)) or turnLeft(B) and turnLeft(B) and (forward(B) or (C and dig() and forward(B))) then if down(B) or (C and digDown() and down(B)) then return true end end
875
			else
876
				if turnLeft(B) and turnLeft(B) and (forward(B) or (C and dig() and forward(B))) or turnLeft(B) and turnLeft(B) and (forward(B) or (C and dig() and forward(B))) then if down(B) or (C and digDown() and down(B)) then return true end end
877
			end
878
			
879
		end
880
	end
881
	
882
	return false
883
end
884
 
885
local function forwardP(A,B,C)
886
	
887
	for i=1,A do
888
	
889
		if forward(B) or (C and dig() and forward(B)) then
890
			return true
891
		else
892
		
893
			if math.random(0,1)==1 then
894
				if up(B) or down(B) or (C and digUp() and up(B)) or (C and digDown() and down(B)) then if forward(B) or (C and dig() and forward(B)) then return true end end
895
			else
896
				if down(B) or up(B) or (C and digDown() and down(B)) or (C and digUp() and up(B)) then if forward(B) or (C and dig() and forward(B)) then return true end end
897
			end
898
			
899
			local dir=math.random(0,1)
900
			
901
			if dir == 1 then turnLeft(B) else turnRight(B) end
902
			
903
			if forward(B) or (C and dig() and forward(B)) then 
904
				if dir == 1 then turnRight(B) else turnLeft(B) end
905
				if forward(B) or (C and dig() and forward(B)) then return true end
906
			elseif turnLeft(B) and turnLeft(B) and (forward(B) or (C and dig() and forward(B))) then			
907
				if dir == 1 then turnLeft(B) else turnRight(B) end
908
				if forward(B) or (C and dig() and forward(B)) then return true end
909
			end
910
			
911
		end
912
	end
913
	
914
	return false
915
916
end
917
918
local function backP(A,B,C) --add back pathfinding as forward one with 180 reverse first later
919
	turnLeft(B)
920
	turnLeft(B)
921
	return forwardP(A,B,C)
922
end
923
924
--Map based
925
926
--use binary to store blocked directions? Inspect everything
927
--if somepalce has only one way in then its 1? that means its blocked.
928
--blocked place is like a block you can't break - so in tunnel it would spread until whole tunnel got marked as blocked.
929
--instead of going to the place you want to go go 1 block in direction that is not blocked but still leads forard to target. 
930
--problem - big holes  that are blocked - need to figure them out. 
931
	
932
933
--##     GOTO     ##--
934
935
local function face(A,B,C)
936
	if pos.xd==A and pos.zd==B then return end
937
	if pos.zd==A and -pos.xd==B then turnLeft(C) return end
938
	if -pos.zd==A and pos.xd==B then turnRight(C) return end
939
	if -pos.xd==A or -pos.zd==B then turnRight(C) turnRight(C) return end
940
end
941
942
util.face = face
943
944
local function fromTo(...) --Distance between 2 points. If given more than 2 points it will claculate minimal fuel to go from first to last in order given
945
	local tArgs={...}
946
	if #tArgs==1 then return 0
947
	elseif #tArgs==2 then return math.abs((tArgs[1].x-tArgs[2].x)) + math.abs((tArgs[1].y-tArgs[2].y)) + math.abs((tArgs[1].z-tArgs[2].z))
948
	else return fromTo(tArgs[1],tArgs[2])+fromTo(unpack(tArgs,2)) end
949
end
950
951
util.fromTo = fromTo
952
metaPoint.__index.fromTo = fromTo
953
954
local function fromTo2d(...) --Distance between 2 points. If given more than 2 points it will claculate minimal fuel to go from first to last in order given. Ignores height.
955
	local tArgs={...}
956
	if #tArgs==1 then return 0
957
	elseif #tArgs==2 then return math.abs((tArgs[1].x-tArgs[2].x)) + math.abs((tArgs[1].z-tArgs[2].z))
958
	else return fromTo2d(tArgs[1],tArgs[2])+fromTo2d(unpack(tArgs,2)) end
959
end
960
961
util.fromTo2d = fromTo2d
962
metaPoint.__index.fromTo2d = fromTo2d
963
964
965
local moves = {} --1 goto, 2 goto + mine obscales, 3 goto + pathfind1, 4 goto + mine obscales then pathfind1 if mine failed, 5 - planned - goto + pathfind then mine if pathfind failed.
966
moves[1] = { 
967
		["up"] = function(C,D) return up(D) end, 
968
		["forward"] = function(C,D) return forward(D) end, 
969
		["down"] = function(C,D) return down(D) end,
970
}
971
moves[2] = {
972
		["up"] = function(C,D) if not up(D) then return digUp() else return true end end,
973
		["forward"] = function(C,D) if not forward(D) then return dig() else return true end end,
974
		["down"] = function(C,D) if not down(D) then return digDown() else return true end end,
975
}
976
moves[3] = {
977
		["up"] = function(C,D)  return upP(C,D) end, 
978
		["forward"] = function(C,D)  return forwardP(C,D) end, 
979
		["down"] = function(C,D)  return downP(C,D) end,
980
}
981
moves[4] ={ --make upPD downPD forwardPD backPD
982
		["up"] = function(C,D) if not up(D) then digUp() return upP(C,D,true) else return true end end,
983
		["forward"] = function(C,D)  if not forward() then dig() return forwardP(C,D,true) else return true end end,
984
		["down"] = function(C,D)  if not down(D) then digDown() return downP(C,D,true) else return true end end,
985
}
986
987
local function BlackTest() -- tests if block you are going to is blacklisted.
988
989
end
990
991
goto = function(A,B,C,D) --A target point, B move mode, C used only for pathfinding - defines how far turtle will move from start point, D Force scanning for duration of goto.
992
	
993
	if A and type(A) == "table" and A.x and A.y and A.z and type(A.x)== "number" and type(A.y)== "number" and type(A.z)== "number" then
994
		B=B or 1 --B=1 is default if B not defined
995
		C=C or 5 --C=5 is default if C not defined
996
		D = true
997
		
998
		local move = moves[B]
999
		if not move then
1000
			error("Illegal movement mode selected.",1)
1001
		end
1002
1003
		while A.x-pos.x ~= 0 or A.y-pos.y ~= 0 or A.z-pos.z ~= 0 do
1004
			
1005
			if getFuelLevel()<fromTo(A,pos) then return false,"Fuel Level Insufficient" end
1006
			
1007
			--going up always takes priority
1008
			if A.y-pos.y > 0 then while A.y-pos.y ~= 0 do if not move.up(C,D) then break end end end
1009
			
1010
			if A.x-pos.x < 0 then face(-1,0) while A.x-pos.x ~= 0 and pos.xd==-1 and pos.zd==0 do if not move.forward(C,D) then break end end  end
1011
			if A.x-pos.x > 0 then face(1,0) while A.x-pos.x ~= 0 and pos.xd==1 and pos.zd==0 do if not move.forward(C,D) then break end  end  end
1012
			
1013
			if A.z-pos.z < 0 then face(0,-1) while A.z-pos.z ~= 0 and pos.xd==0 and pos.zd==-1 do if not move.forward(C,D) then break end end  end
1014
			if A.z-pos.z > 0 then face(0,1) while A.z-pos.z ~= 0 and pos.xd==0 and pos.zd==1 do if not move.forward(C,D) then break end end end
1015
			
1016
			if A.y-pos.y < 0 then while A.y-pos.y ~= 0 do if not move.down(C,D) then break end end end
1017
			
1018
			sleep(0.05)
1019
		end
1020
	else
1021
		return false,"Invalid point"
1022
	end
1023
	
1024
	if A.xd and A.zd then
1025
		face(A.xd,A.zd)
1026
	end
1027
1028
	return true
1029
	
1030
end
1031
metaPoint.__index.goto = goto
1032
1033
1034
--##     Daemon     ##--  
1035
--Only if _WojbieStarter = true
1036
1037
if _WojbieStarter then
1038
	local bRunning = false
1039
	
1040
	local bOn = false
1041
	local nCur = false
1042
	
1043
	runDaemon = function(apiName,apiTable) --deamon version for custom coorutine menager. Works like rednet.run
1044
		if bRunning then
1045
			error( "Daemon is already running", 2 )
1046
		end
1047
		bRunning = true
1048
		
1049
		--load patches from .tPatch/
1050
		if fs.exists("/.tPatch") and fs.isDir("/.tPatch") then
1051
			for i,k in pairs(fs.list("/.tPatch")) do
1052
				tags.loadTagPatch(fs.combine("/.tPatch",k))
1053
			end
1054
		end
1055
		
1056
		--Modem watchdog - ensures that gps chanel is always open.
1057
		local sModemSide = nil
1058
		
1059
		local function testModem() -- Find a modem
1060
			if sModemSide and peripheral.getType( sModemSide ) == "modem" and peripheral.call( sModemSide, "isWireless" ) and peripheral.call( sModemSide, "isOpen" , gps.CHANNEL_GPS) then
1061
				return true
1062
			end
1063
			sModemSide = nil
1064
			for n,sSide in ipairs( rs.getSides() ) do
1065
				if peripheral.getType( sSide ) == "modem" and peripheral.call( sSide, "isWireless" ) then	
1066
					local ok = pcall(peripheral.call,sSide, "open" , gps.CHANNEL_GPS) --overdrawing on channels test.
1067
					if ok then sModemSide = sSide break end
1068
				end
1069
			end
1070
			return sModemSide and true
1071
		end
1072
		
1073
		-- Open a channel
1074
1075
		--Main daemon part - GPS host and fuel labeler.
1076
		local tEvents
1077
		local timer = os.startTimer(1)
1078
		
1079
		while true do
1080
			tEvents={os.pullEventRaw()}
1081
			
1082
			--Gps responding
1083
			--"modem_message" Side Channel ReplyChannel Message Distance
1084
			if bOn and (not bInMove) and tEvents[1] == "modem_message" and testModem() and tEvents[2] == sModemSide and tEvents[3] == gps.CHANNEL_GPS and tEvents[5] == "PING" then 
1085
				peripheral.call( sModemSide, "transmit", tEvents[4] , gps.CHANNEL_GPS, { pos.x, pos.y, pos.z } )
1086
			
1087
			--Local turtle menagement.
1088
			--"timer nTimer
1089
			elseif tEvents[1] == "timer" and tEvents[2] == timer then
1090
				timer = os.startTimer(1)
1091
				 --Retesting modem.
1092
				if bOn then testModem() end
1093
				 --Retesting fuel label.
1094
				if nCur and os.getComputerLabel() and nCur ~= getFuelPercent() then os.setComputerLabel((string.match(os.getComputerLabel(),"^(.+) %[[%d%.]-%%%]$") or os.getComputerLabel()).." ["..(math.floor(turtle.getFuelPercent()*1000)/10).."%]") nCur = getFuelPercent() end end
1095
		end
1096
	end
1097
	
1098
	util.setDaemonGps = function(A) bOn = A and true end
1099
	util.getDaemonGps = function() return bOn and true end
1100
	util.setFuelLabel = function(A) if A and os.getComputerLabel() then nCur = -1 elseif os.getComputerLabel() then os.setComputerLabel(string.match(os.getComputerLabel(),"^(.+) %[[%d%.]-%%%]$") or os.getComputerLabel()) nCur = false end end
1101
	util.getFuelLabel = function() return nCur and true end
1102
	
1103
end
1104
1105
--##     PERIPHERAL FIXER     ##--
1106
util.peripheralFix = function()
1107
--Detect
1108
--Fix
1109
--End
1110
end
1111
1112
--##     TURTLE FUNCTIONS DUPLICATOR     ##--
1113
--in case this api is loaded onto turtle api.
1114
1115
local env = _ENV
1116
for k,v in pairs( oldturtle ) do
1117
	if not rawget(env, k) then env[k] = v end -- place the value defined before or use oldturtle one
1118
end