From e1e4ec871bb84b1d818b3a3760c39c892895def4 Mon Sep 17 00:00:00 2001 From: Jack O'Sullivan Date: Mon, 15 Jan 2024 13:14:17 +0000 Subject: [PATCH] Initial commit --- PriorityQueue.lua | 232 ++++++ alarm.lua | 61 ++ danger.dfpwm | Bin 0 -> 37546 bytes datapack/.gitignore | 1 + .../turtle_upgrades/diamond_pickaxe.json | 6 + datapack/pack.mcmeta | 6 + icon/ore-coal.png | Bin 0 -> 623 bytes icon/ore-copper.png | Bin 0 -> 653 bytes icon/ore-diamond.png | Bin 0 -> 625 bytes icon/ore-ds-coal.png | Bin 0 -> 613 bytes icon/ore-ds-copper.png | Bin 0 -> 636 bytes icon/ore-ds-diamond.png | Bin 0 -> 641 bytes icon/ore-ds-emerald.png | Bin 0 -> 636 bytes icon/ore-ds-gold.png | Bin 0 -> 615 bytes icon/ore-ds-iron.png | Bin 0 -> 624 bytes icon/ore-ds-lapis.png | Bin 0 -> 661 bytes icon/ore-ds-redstone.png | Bin 0 -> 715 bytes icon/ore-emerald.png | Bin 0 -> 634 bytes icon/ore-generic.png | Bin 0 -> 12244 bytes icon/ore-gold.png | Bin 0 -> 633 bytes icon/ore-iron.png | Bin 0 -> 615 bytes icon/ore-lapis.png | Bin 0 -> 676 bytes icon/ore-redstone.png | Bin 0 -> 644 bytes icon/turtle.png | Bin 0 -> 8745 bytes mine.lua | 727 ++++++++++++++++++ mineMonitor.lua | 185 +++++ tree.lua | 134 ++++ 27 files changed, 1352 insertions(+) create mode 100644 PriorityQueue.lua create mode 100644 alarm.lua create mode 100644 danger.dfpwm create mode 100644 datapack/.gitignore create mode 100644 datapack/data/minecraft/computercraft/turtle_upgrades/diamond_pickaxe.json create mode 100644 datapack/pack.mcmeta create mode 100644 icon/ore-coal.png create mode 100644 icon/ore-copper.png create mode 100644 icon/ore-diamond.png create mode 100644 icon/ore-ds-coal.png create mode 100644 icon/ore-ds-copper.png create mode 100644 icon/ore-ds-diamond.png create mode 100644 icon/ore-ds-emerald.png create mode 100644 icon/ore-ds-gold.png create mode 100644 icon/ore-ds-iron.png create mode 100644 icon/ore-ds-lapis.png create mode 100644 icon/ore-ds-redstone.png create mode 100644 icon/ore-emerald.png create mode 100644 icon/ore-generic.png create mode 100644 icon/ore-gold.png create mode 100644 icon/ore-iron.png create mode 100644 icon/ore-lapis.png create mode 100644 icon/ore-redstone.png create mode 100644 icon/turtle.png create mode 100644 mine.lua create mode 100644 mineMonitor.lua create mode 100644 tree.lua diff --git a/PriorityQueue.lua b/PriorityQueue.lua new file mode 100644 index 0000000..9d4cb0e --- /dev/null +++ b/PriorityQueue.lua @@ -0,0 +1,232 @@ +--[[ + + PriorityQueue - v1.0.1 - public domain Lua priority queue + implemented with indirect binary heap + no warranty implied; use at your own risk + + based on binaryheap library (github.com/iskolbin/binaryheap) + + author: Ilya Kolbin (iskolbin@gmail.com) + url: github.com/iskolbin/priorityqueue + + See documentation in README file. + + COMPATIBILITY + + Lua 5.1, 5.2, 5.3, LuaJIT 1, 2 + + LICENSE + + This software is dual-licensed to the public domain and under the following + license: you are granted a perpetual, irrevocable license to copy, modify, + publish, and distribute this file as you see fit. + +--]] + +local floor, setmetatable = math.floor, setmetatable + +local function siftup( self, from ) + local items, priorities, indices, higherpriority = self, self._priorities, self._indices, self._higherpriority + local index = from + local parent = floor( index / 2 ) + while index > 1 and higherpriority( priorities[index], priorities[parent] ) do + priorities[index], priorities[parent] = priorities[parent], priorities[index] + items[index], items[parent] = items[parent], items[index] + indices[items[index]], indices[items[parent]] = index, parent + index = parent + parent = floor( index / 2 ) + end + return index +end + +local function siftdown( self, limit ) + local items, priorities, indices, higherpriority, size = self, self._priorities, self._indices, self._higherpriority, self._size + for index = limit, 1, -1 do + local left = index + index + local right = left + 1 + while left <= size do + local smaller = left + if right <= size and higherpriority( priorities[right], priorities[left] ) then + smaller = right + end + if higherpriority( priorities[smaller], priorities[index] ) then + items[index], items[smaller] = items[smaller], items[index] + priorities[index], priorities[smaller] = priorities[smaller], priorities[index] + indices[items[index]], indices[items[smaller]] = index, smaller + else + break + end + index = smaller + left = index + index + right = left + 1 + end + end +end + +local PriorityQueueMt + +local PriorityQueue = {} + +local function minishigher( a, b ) + return a < b +end + +local function maxishigher( a, b ) + return a > b +end + +function PriorityQueue.new( priority_or_array ) + local t = type( priority_or_array ) + local higherpriority = minishigher + + if t == 'table' then + higherpriority = priority_or_array.higherpriority or higherpriority + elseif t == 'function' or t == 'string' then + higherpriority = priority_or_array + elseif t ~= 'nil' then + local msg = 'Wrong argument type to PriorityQueue.new, it must be table or function or string, has: %q' + error( msg:format( t )) + end + + if type( higherpriority ) == 'string' then + if higherpriority == 'min' then + higherpriority = minishigher + elseif higherpriority == 'max' then + higherpriority = maxishigher + else + local msg = 'Wrong string argument to PriorityQueue.new, it must be "min" or "max", has: %q' + error( msg:format( tostring( higherpriority ))) + end + end + + local self = setmetatable( { + _priorities = {}, + _indices = {}, + _size = 0, + _higherpriority = higherpriority or minishigher + }, PriorityQueueMt ) + + if t == 'table' then + self:batchenq( priority_or_array ) + end + + return self +end + +function PriorityQueue:enqueue( item, priority ) + local items, priorities, indices = self, self._priorities, self._indices + if indices[item] ~= nil then + error( 'Item ' .. tostring(indices[item]) .. ' is already in the heap' ) + end + local size = self._size + 1 + self._size = size + items[size], priorities[size], indices[item] = item, priority, size + siftup( self, size ) + return self +end + +function PriorityQueue:remove( item ) + local index = self._indices[item] + if index ~= nil then + local size = self._size + local items, priorities, indices = self, self._priorities, self._indices + indices[item] = nil + if size == index then + items[size], priorities[size] = nil, nil + self._size = size - 1 + else + local lastitem = items[size] + items[index], priorities[index] = items[size], priorities[size] + items[size], priorities[size] = nil, nil + indices[lastitem] = index + size = size - 1 + self._size = size + if size > 1 then + siftdown( self, siftup( self, index )) + end + end + return true + else + return false + end +end + +function PriorityQueue:contains( item ) + return self._indices[item] ~= nil +end + +function PriorityQueue:update( item, priority ) + local ok = self:remove( item ) + if ok then + self:enqueue( item, priority ) + return true + else + return false + end +end + +function PriorityQueue:dequeue() + local size = self._size + + assert( size > 0, 'Heap is empty' ) + + local items, priorities, indices = self, self._priorities, self._indices + local item, priority = items[1], priorities[1] + indices[item] = nil + + if size > 1 then + local newitem = items[size] + items[1], priorities[1] = newitem, priorities[size] + items[size], priorities[size] = nil, nil + indices[newitem] = 1 + size = size - 1 + self._size = size + siftdown( self, 1 ) + else + items[1], priorities[1] = nil, nil + self._size = 0 + end + + return item, priority +end + +function PriorityQueue:peek() + return self[1], self._priorities[1] +end + +function PriorityQueue:len() + return self._size +end + +function PriorityQueue:empty() + return self._size <= 0 +end + +function PriorityQueue:batchenq( iparray ) + local items, priorities, indices = self, self._priorities, self._indices + local size = self._size + for i = 1, #iparray, 2 do + local item, priority = iparray[i], iparray[i+1] + if indices[item] ~= nil then + error( 'Item ' .. tostring(indices[item]) .. ' is already in the heap' ) + end + size = size + 1 + items[size], priorities[size] = item, priority + indices[item] = size + end + self._size = size + if size > 1 then + siftdown( self, floor( size / 2 )) + end +end + +PriorityQueueMt = { + __index = PriorityQueue, + __len = PriorityQueue.len, +} + +return setmetatable( PriorityQueue, { + __call = function( _, ... ) + return PriorityQueue.new( ... ) + end +} ) diff --git a/alarm.lua b/alarm.lua new file mode 100644 index 0000000..128e7fa --- /dev/null +++ b/alarm.lua @@ -0,0 +1,61 @@ +local dfpwm = require("cc.audio.dfpwm") + +local speaker = peripheral.find("speaker") +local monitor = peripheral.find("monitor") +local chat = peripheral.find("chatBox") +local detector = peripheral.find("playerDetector") + +local distance = 20 +local target = "OROURKEIRE" +--local target = "devplayer0" + +function klaxon() + local decoder = dfpwm.make_decoder() + for chunk in io.lines("data/danger.dfpwm", 16 * 1024) do + local buffer = decoder(chunk) + + while not speaker.playAudio(buffer) do + os.pullEvent("speaker_audio_empty") + end + end +end + +function showWarning() + monitor.clear() + monitor.setTextScale(2) + --[[local w, h = monitor.getSize() + local tw = string.len("WARNING") + for i = 1, 3 do + monitor.setCursorPos(w/2 - tw/2, (h/3)*i) + monitor.write("WARNING") + end]] + monitor.setCursorPos(8, 3) + monitor.write("WARNING") + monitor.setCursorPos(8, 5) + monitor.write("WARNING") + monitor.setCursorPos(8, 8) + monitor.write("WARNING") +end + +function broadcastWarning() + local msg = { + {text = "WARNING", color = "red"}, + {text = ": Kevin is ", color = "white"}, + {text = "IN THE BASE", color = "yellow"}, + {text = "!"}, + } + local msgJSON = textutils.serializeJSON(msg) + chat.sendFormattedMessage(msgJSON) +end + +while true do + if detector.isPlayerInRange(25, target) then + showWarning() + broadcastWarning() + klaxon() + else + monitor.clear() + end + + sleep(1) +end diff --git a/danger.dfpwm b/danger.dfpwm new file mode 100644 index 0000000000000000000000000000000000000000..2f5a0e6ca38df5feb282bf8895962bb0a246a41d GIT binary patch literal 37546 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 G0{b8sH&=3+L!@>o}Qkk zxBdVB{~t7*7XvD0O!9Vj;mWx1B@D=6FY)wsWq-lQC!}H;+-e^Vlvek2aSX}0_jbl@ z-a`fgESH_47O=w6uA|K}GB)0E@Y^omS=|3Hy>#2nZJxg`JXODbePPeiZERB*cAQ|l zw|#=?_4z%4w;QY&&Mr#S*uihxHqW_+yN*}zw{Z}&7lY0TrP=qLYnXj5uVlNz@Ik?| zP_5xs$0zrq=1d3P1K$m0^^Dqtx@2tJgPHyK3lcw{GT0+&z&FdL#AE^Afn_!k0drc{ zbZ)-*M{+HrDuWZpEgwN?-U%{B+Rdg5*c^g0RP;qGBZ?kh44Jit(Ud_(EUn|@)W)J0 z7j8F5HQbaDlN6uyGlcmSgGsw|*K}WY&dQ=0?H0ZN3aK8k5OcwAYu%7HbvFaOx=>nz)%*LvF*2KN~a~&9pswJ)wB`Jv|saDBF zsX&Us$iT=%*T7KM&?Lmr!phjt%E(CDz`)ADV8gxJawr;d^HVa@DnS~Ibq&mP4UIz# zjjfE$tPD&b8q8~VI07|jz-=hW%uOvWNz5%kx5UiK)EJ`Y#*gTgKs^keu6{1-oD!M< DGj`Ws literal 0 HcmV?d00001 diff --git a/icon/ore-copper.png b/icon/ore-copper.png new file mode 100644 index 0000000000000000000000000000000000000000..299e72843fb4d9f186d5e4605938f6a4ea4e89f2 GIT binary patch literal 653 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?I3?vN&YJLDIg=CK)Uj~LMHK2G41H&(n{0jz# zQUeBtR|yOZRx=nF#0%!^3bX-A=mz+Nxc2w=*VosVl$2y-WLT9Y$Hc@uDE2*=?zU*r zqQ-`Z&rKOt8Bvi_8~u09`2YX^mc#E`ff^Z;yxm>+^7k6}13By^p1!W^FBtiRl$n-P z^2`THTY9=UhGg7(J0p`R4zKYgCEJa(Gj z^a;naGq~6KPFH)hltGi>uhaY&w`SGsXQ*U|+F_>o@Y|yD%_k8Xovd)lt zuTUp+f$4$SCtp4?h$wz6Q^>Mic=|IK;nAutdbR7+eVN>UO_QmvAUQh^kMk%5tku7RPhp-G6Lg_W_P zm64IQfq|8Q!G?Rcl&Ep8XAWf8e18gSs9o>G?>@!a0F`5fZI@# jnVVW%l9*e7Zi%Ut0o0Pa5l^dtdKf%i{an^LB{Ts5a7E!_ literal 0 HcmV?d00001 diff --git a/icon/ore-diamond.png b/icon/ore-diamond.png new file mode 100644 index 0000000000000000000000000000000000000000..6659b080194e9733096380a66c39159544e594b4 GIT binary patch literal 625 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?I3?vN&YJLDIg=CK)Uj~LMHK2G41H&(n{0jz# zQUeBtR|yOZRx=nF#0%!^3bX-ACpBu$=lt9E91hKFd&D$#M9T6{RJbRkcQ6e=o_ReJ4-rWC~1}eRq9kBQ9>2N^qW10{rMS~D-QB_Fkk3h+u>a`!+8Fpy(?y(ZxCs?XW$;V=Bt6}UG^*o zK8Aw^T)h?&;wA+<{iDkzd~}wTsjS7U-#jzq7Mwh^aBY_XC&&G4b>BJmUqEKdAa7+P2v8(J9|X&V?=85nH1cUulcLvDUb zW?CgkgR!oGnXaL6h@r8Sv6+>D2}FZ=?G8tv1`W6kC7HRY#U+Wk1!$I-7+9G=^?bd+ RPz%(<;OXk;vd$@?2>`?+*Gm8Z literal 0 HcmV?d00001 diff --git a/icon/ore-ds-coal.png b/icon/ore-ds-coal.png new file mode 100644 index 0000000000000000000000000000000000000000..5c17500e1d331d90fdbc0ac86af855b82b1bd3c8 GIT binary patch literal 613 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?I3?vN&YJLDIg=CK)Uj~LMHK2G41H&(n{0jz# zQUeBtR|yOZRx=nF#0%!^3bX-A$OZU>xK>tHrlh0<1_s*NI_vA3b8&HLX=%yJ%X@m; z|NsBLfZ?eXP$grMx4R4H$D2#v06FX>p1!W^FBtiRR2gJ+PniOx6+B%WLo)8YogT=0 z*nr2yd!dM1qKH=_h-9nYxk`Umq^iK{cgu5g_WzrclYYDH+d}t?pD*Qol6W7@pvxd5 zGhM^RXRAcRJjO2!2|_%spR!-no_si8aV{g*0(OSr9g!ZB_BsC&yHM{`$6(7~#IbCl z=L84EqgQj5Ph`qq+`;X^Bl2jD=aUMXhOdlqZ@OFcrx;1~9!mzAR#7}5L(l7&&l7_T zgD{3#29ejE8z(gc#LPZz5(Kol?qbTyfQ{jc`5$gt%1CuM4JDhGa z7hpSQGEuw1j3M4cMY3(_;n}BkRT`!;+J`i(J##8)8Zc%UR7+eVN>UO_QmvAUQh^kM zk%5tku7RPhp-G6Lg_W_Pm64IQfq|8Q!G?Rcl&Ep8XAWf8e18g ySs9o>G?>@!a0F`5fZI@#nVVW%l9*e7ZizY2c!(Z9Bb7X$9tKZWKbLh*2~7Z8y3OtHrlh0<1_s*NI_vA3Ta_h0DE2*=?$+24 z@wq9(DkCa#YNP+I8UO$PpHq3-3#f}R$=lt9_uH1luRsoaiKnkC`wK=sA!SbE)mO!V z(%PObjv*QM-cAn`JmkRRlD$xDLjZTg0VWtF;5u#R^~g(78EU@|pH=<+<7Cdd%ObO! zr!Ps(FstnSe5FB%L2sS2_oP=d_Oiz_XEB6ad7A6dT*`9gr(9Lbi%bXE2L5g?E9TRt zPZ%#ZNHOqpoXPH3cu~^X>_6K|MpXt6@vLc{&(cruTBejSUu(F`{Ez9-6Mjy~>x%6r z3)l`EKFEHQ`H5&%yPe|StQ#B)*sd__n7Q;(@G*IYk4rbJ1~U8c2N*jaTCn2e**~1} zDsmRQD;O7ey3W*0`n2F--S-_C4xA19E&iTi`q=KqH=FGWCKxs>H3_e#d)Y&DF>Lj0oz zUb+Ayh(Wc)HKHUXu_VKdAa7+P2v8(J9|X&V?=85nH1cUulc zLvDUbW?CgkgR!oGnXaL6h@r8Sv6+>D2}FZ=?G8tv1`W6kC7HRY#U+Wk1?ZNTS{YbE V^xTi%*Z|bS;OXk;vd$@?2>`~t-RuAW literal 0 HcmV?d00001 diff --git a/icon/ore-ds-diamond.png b/icon/ore-ds-diamond.png new file mode 100644 index 0000000000000000000000000000000000000000..4c0a8c8c8719bfd81c0dff5879318cfe22a772fe GIT binary patch literal 641 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?I3?vN&YJLDIg=CK)Uj~LMHK2G41H&(n{0jz# zQUeBtR|yOZRx=nF#0%!^3bX-As0a9jxK>tHrlh0<1_s*NI_vA38#*}1UAR{M{Gv$z zq?E3ntN*_xR+j(&|KF>Lw*jbyG0EHAg{N_IU^0-yUgGKN%Kn0pPe?2i;(`xME#S9xIv>FNiXmx2PIuBNE4P(}Eh z+3SGv&UP|JD4DLD1rx-lcF8p1%q@Fhe=(-HC zEf4JH-ARZFUSz)LiRl8i1LxV9ZY=41Q1I{o2OC7#SFu=o%R68k&R{T38tyS{WH>8yHv_7;LzA zTMk7-ZhlH;S|vz>v95ucuAy;=p|O>*nU#SFM1y(l4o9E{4Y&;@nYpROC5gEOXqK25 ZSQ%SD^jK_7769sD@O1TaS?83{1OO#C-t+(f literal 0 HcmV?d00001 diff --git a/icon/ore-ds-emerald.png b/icon/ore-ds-emerald.png new file mode 100644 index 0000000000000000000000000000000000000000..8169c95fb03f20a1dcbd68f1b8cf64a64db60e1f GIT binary patch literal 636 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?I3?vN&YJLDIg=CK)Uj~LMHK2G41H&(n{0jz# zQUeBtR|yOZRx=nF#0%!^3bX-As0a9jxK>tHrlh0<1_s*NI_vA3-~9ht{B9CMwS;-J zo#W>gnHiemM_vB^|Ici2G!UqTG0EHAg{N_IU^0-yUgGKN%Kn0pPe@Hf_m*!rP+HH^ z#W5t~-rE_0f`=Svj zKD(fsDLKnG?(z344MGfj*A}XJmd-4ejc3kc(75N^Kf(M=)}nLA8B7QCBaTx9Mvyk_398-ZQyAv3dLA&!yjk%g z;fBcqz68Uk?Vb;$ROGDw$*D*eR65+_moxjMEXtjpuN2OFiXlQGM(n_Jj&eUm-W^5{ z*zd-c&US2D1Byx264!{5l*E!$tK_0oAjM#0U}U0eV5no#l1||><=CwNxK>tHrlh0<1_s*NI_vA3&q+~uJ(us#JMaJh zxBmbCUvd3RJ)la)ByV>Y&W|^jz5#OBOFVsD* zg3Sgz&XEhXOIX7afT(rdg^kjMm2+N|G1gr2SBQA;EpDxI`a<%H$Sr)CwKHCsXL2rJ zZRpL-k{8ee6?-(&0I4a{hT&g%7M{lz(5l_RRSnPI+Jes+PD$l%yncps|0B<)-^EGH8c(} zG`2D}vobJ&XfUtc;Rw{A0k@$fGdH!kBr&%D-4b&vLkozWjpbR>fqED`UHx3vIVCg! E04uoK{r~^~ literal 0 HcmV?d00001 diff --git a/icon/ore-ds-iron.png b/icon/ore-ds-iron.png new file mode 100644 index 0000000000000000000000000000000000000000..34afe0262684275d1d3414dfd4b4420f6721e749 GIT binary patch literal 624 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?I3?vN&YJLDIg=CK)Uj~LMHK2G41H&(n{0jz# zQUeBtR|yOZRx=nF#0%!^3bX-ACtHrlh0<1_s*NI_vA3m#6!8l!UJDE5EUR z@}mQ*{{R19xIHNjsF*Ry+uemL#1tXu3ve3?RGQWY+8lEnWAsP4H z&J5&bG8AyhX5@}Iz$CVzfmJ7gaeIkJ{HJvX59F5F?I?P?@1M`IXo=)kMx}R4qIY@B zOSX{;U^>wK`%-T3v*157s`OHQVwtlT3_R81f-9vsOxlutkL6rwkZPzg_&D#>6FHe2 zqiHe*yek+t1m*}FIAA!lyS|iHgV90a*s?CW;7TEt$m3G8S2I3mmtjgeDKPs?``LxT zxd&D<^08-o#65n*c7<`rLX;jO6={tZiP*3 z7LAu1q!>gx{#QJ3I62ulynIsZ%obzvpRfEO#T_m?8UIp;G)a!5S6#_z+hA@ zag8WRNi0dVN-jzTQVd20MkcxjhPs9(A%+%K#)ei#M%o4jRt5$e?%kF{(U6;;l9^Ts z(qOD>V5Vzm9Aao}Wo%|;U;@!#Uc18)s6hj6LrG?CYH>+oZUMR_rdEa)5ItL)cC7;H OVeoYIb6Mw<&;$Tz+t#80 literal 0 HcmV?d00001 diff --git a/icon/ore-ds-lapis.png b/icon/ore-ds-lapis.png new file mode 100644 index 0000000000000000000000000000000000000000..b17297cb5f13ac04dff2105cf0a44898b7165ff2 GIT binary patch literal 661 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?I3?vN&YJLDIg=CK)Uj~LMHK2G41H&(n{0jz# zQUeBtR|yOZRx=nF#0%!^3bX-AXa)F$xK>tHrlh0<1_s*NI_vA3ON8!Ki0l?~=@l^9 zE8w!mCI3$5)Gq=ibN>JT?=KMF3Dm`yx9?9~?G4a%!G~|Fgb5OivgBRJLERUGi1%Q$o9)^R944F$MmHMF%35 zgnOj3&QpA6CVVusL59J+BTq=AllA_Se2g!s%;*gSFO4*?^QaK>ru8P1m{ zH12VZ$}|wVZ!4#)b>J6+Y={Y$gjTkZu>EdEQ3dt`-A8;~t9@D@24A{4JCL!6p-pk2 zsl=={1~0qW3@@xF0Ns)x7Nt2aPfRi2%x1x6w!U`;K+7hCsLWT(SE}XO7{NB-{$o}T z<^>A{G&-6MMS9vENyTX%xYTfXNm^s&iiH|8Hcv7Tk$W|FCBtdvw9N?%9z5Ty{^NtA zvzCJ$!}NI$8z+1b4{Dgo7=KD{@9hhFyLJGBShd78q9i4;B-JXpC>2OC7#SFu=o%R6 z8k&R{T38tyS{WH>8yHv_7;LzATMk7-ZhlH;S|vz>v95ucuAy;=p|O>*nU#SFM1y(l s4o9E{4Y&;@nYpROC5gEOXqK1&jW>npx&D^b7^sKA)78&qol`;+09aDsUjP6A literal 0 HcmV?d00001 diff --git a/icon/ore-ds-redstone.png b/icon/ore-ds-redstone.png new file mode 100644 index 0000000000000000000000000000000000000000..07c2dd17901043c73be0d852a92d63875f0277bb GIT binary patch literal 715 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H3?#oinD`S&DI|LY`7$t6sR6}X7#MzmnTu$sZZAYL$MSD+10!Z^Su#I>@rG9@J?Ffh>8)>&WQ+}GUPT1RIZ8`~*% z_WukFf8*kgv9L^MX8zyV*%BG~T}I~r|Nn7U1D*o4GbVYvy9i9(#H$13u$OrHy0X7u zEe)O=I>;}uwt1<6zJW~o{VRe%rB)3&b6EE{yiwJ>!>6J-qnqdZSsO+s zmNV=ri_0Enuye|V+>)Pu=ljd<4xmlb7&mNuqHsx1C-VLRmS^SHL_r2Hh&^L$t+#n% zd40LU^XHcF5e*ECpBddf`2_YPY&mwc`Q%MURgg_J2X5Lnig$-~ye@yTl5r~sFhnF7 z#ET9y80G1INCz4JPx=G*T`sN(UI#uU1LH%r#5JNMC9x#cD!C{XNHG{07@6oA80s3D zgcw>_85>#|8EG3BSQ!{>xOZC)MMG|WN@iLmNQ1GiftjwMafqR@m9d$XfeA!|dF>8I ppau=N4JDbmsl_FUxdrH!SXdcAEzww(cM7P7!PC{xWt~$(69BFB`E>vQ literal 0 HcmV?d00001 diff --git a/icon/ore-emerald.png b/icon/ore-emerald.png new file mode 100644 index 0000000000000000000000000000000000000000..6d158b34e8925f56cb67cd3317883e8c5bfa57d4 GIT binary patch literal 634 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?I3?vN&YJLDIg=CK)Uj~LMHK2G41H&(n{0jz# zQUeBtR|yOZRx=nF#0%!^3bX-As0a9jxc2w=*VosVl$2y-WCUdg-2DGq{B9CMwS;-J zo#W>gnHiemM_vB^|6g>GTNbE=G0EHAg{N_IU^0-yUgGKN%Kn0pPe@JbR8m3@P+G^+ z#W5t~-rE_mf`=Svbz*wAOy?yTbnMw<0zVTlF^Jm4$m}z|z zx3uU5+r>Ng1TJP&Ww5)mtZ&5`>9h*wR}52jw975DF|abOxA5TAV4N_erp+QkM(cU$ zJ_p_vj3-Vzv1Zk^N-Vx{xj~9Se8UIZubiCE7Jdx+SiE5)<8rnN4UsD!Rs?#xOmAn9 z)8IRQuE%5n&jCi}JAZgJk0qW;Tg+(6V7Wlew7B!h)8x$?Yr%Hc7ZyvSArxDT55pERVgbJx{kSbN=|& z-<{cuVTa15n+74`CnvsqppKdAa7+P2v8(J9|X&V?=85nH1 zcUulcLvDUbW?CgkgR!oGnXaL6h@r8Sv6+>D2}FZ=?G8tv1`W6kC7HRY#U+Wk1?ZMo ZSQ(i?^vpZsy9B6*!PC{xWt~$(69BsH;En(Q literal 0 HcmV?d00001 diff --git a/icon/ore-generic.png b/icon/ore-generic.png new file mode 100644 index 0000000000000000000000000000000000000000..ecd9808639c827b81a55518774ffcf64fe17af1b GIT binary patch literal 12244 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 literal 0 HcmV?d00001 diff --git a/icon/ore-gold.png b/icon/ore-gold.png new file mode 100644 index 0000000000000000000000000000000000000000..625ae904277a25dc5e70baa6cda0abfcac8e1656 GIT binary patch literal 633 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?I3?vN&YJLDIg=CK)Uj~LMHK2G41H&(n{0jz# zQUeBtR|yOZRx=nF#0%!^3bX-AC3}LJ(us#JMTq{ z7XAOf_5c6>HOt;!0xD)q@^*LO%DC_)49H6ou zu`lBm27`n`UBl&0_xJGRs%A00U_PKT>C6$egLhnRU$82X(rgf8n8lfvczO2{b+z5I z`4_Ms;P1}nBvCK(5LhJ%w1vlu5T@XMRX9!n4AeDINh%|x)LSofX}OW$D+ zpqoB8eO558X#RM5ncb6Y#xD#NiyiV5^35h4dVb$krNN9r@=&kSf+y7x?Xkfj^+w^ttRHF^+=@0=Y;dXj;L&mk7!?A~7`rPn&@C~y XGJ@*)5y1}B!oc9^>gTe~DWM4fAi&?D literal 0 HcmV?d00001 diff --git a/icon/ore-iron.png b/icon/ore-iron.png new file mode 100644 index 0000000000000000000000000000000000000000..9b0f5fdeb4fb2f7ce65cd02fc741697a9ee57129 GIT binary patch literal 615 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?I3?vN&YJLDIg=CK)Uj~LMHK2G41H&(n{0jz# zQUeBtR|yOZRx=nF#0%!^3bX-A$OZU>xc2w=*VosVl$2y-WR$1-ca(&#?<>Ete)6LO ztN#E0FZn_!4XBba$=lt9^W)8>Z-5;35>H=O_7{wNLdueQGDnMn(n_8#jv*QM-p;tl z+iW1<9N8!u(I~phDf|Uj?80R8X%!QTlNkNJ@heWZsndx+w2k+z>v7d%&o2aS*~wI4 zbHIG=^ckN`*Dw68+Iv&jLB4@atETPC5tlrLy_=8uiaW?Nw7wTOR+!9Kbop!o=K|IR zWs>(j8fx@1V;UL1FkEmj=$!5Ki}$7Hgo+<$)(IbY%qS<4r_o+<;>WI+M;M|Q{x~>B zSgbLdbyviJpJCC&6AoJ|3vLGZCO@0b&-x*QAuXV>*@ah#e@4~@hAIXQ4mHb=gmt^q zHpN&lWia087Mq;&`n*@u(btS$7z-*cT-Fz^`o7HR!Vmt{K-DT@6%`EMmMvN^Q{2xy zn4zD2gQI}G%e~f~{5e}0ZZXsdzL!yW_v&;FgDgY+V!y|Cx0fFG00y9HiEBhjN@7W> zRdP`(kYX@0Ff!3KFw`|P2{E*=GB&g_GSW6Mure^%aPPJpiiX_$l+3hBkOpI212bJi z;}An*D`PV&0~3e_^V%JbKn)sj8%i>BQ;SOya|_TdF|{%>h3JX8b*B@khr!d;&t;uc GLK6VwN!!H$ literal 0 HcmV?d00001 diff --git a/icon/ore-lapis.png b/icon/ore-lapis.png new file mode 100644 index 0000000000000000000000000000000000000000..214e21bd91692c8c6c986cae434dc64074b4b7c2 GIT binary patch literal 676 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?I3?vN&YJLDIg=CK)Uj~LMHK2G41H&(n{0jz# zQUeBtR|yOZRx=nF#0%!^3bX-A=mz+Nxc2w=*VosVl$2y-WW>b8NQCZHi0l?~=@l^9 zyJ*oO0hcu{`FAp>ei1O4^Z)<+^7k6}13By^p1!W^FBtiRG#FMk zZ>a!E2Y9+ThGg7(JHxS%*^!5(ze#h3lST^=HEBYT(~gweH}6TQhyGjd_4(%Rt;^zr zC!ITPSTgI=Pn)NoPY2wSt-spvmT{J5)!a)T*0@zLzhbDUkgk${w1+2kqaxEc!z1st zYj`yn4K(IlS3GxKkw@fSn~~2ol`V|FnPtQ*1B@JI?Y+FG=}LnTgY%T;=4DPZiWXeR z$xxdi&*snU#lXYr#+9KE?>xsu=K;)Fj6s$@e*Rx39AJCH_k(f2P<~~FmrVmOxK&GBBT7;d zOH!?pi&B9UgOP!eiLQa6uAxbYp@o&Pp_P%5wt<0_fx(7*x8+bYV!YkGK7w1JuZvNOxn{$b6%ZhIHO*BCNpdQ-xqI8 zPEXp>woPx{_X+P-iZOdJ?6}bMwf&pkSYBhF#f`2*#1n)&1eD3g1;@ZG@UdYK3ca_v{Za(VEErMBj177K~Ca^ zwacu-D;$_#F;vXBz}&_sl&dy{@hd}yfP|8Smipw9!W#xk zCZMCSImTwY4N&xg%?$&In<1Z4oB3p(Nd_=4c$RoEry-@ecPnEmg9)oNx4qVfH3IJz z_o*2#U{jE8KJ097b|Ykl^(@bMc5Hui9eR%}sd;ITt+Bk`YynHcvYCxv?lMRPFn(a= ze4}4o^RxUgFgR69Tq8p{}7xh@pj*v7wcbk+y+>m4U&A zd$;9KH00)|WTsVuG#Kj|nCTiChZq`L8Jk%dm_Rg`*Y0oxYS4h&P?DLOT3nKtTYzqf Yxs|CgRF9Rxbf6vvPgg&ebxsLQ0JR6*e*gdg literal 0 HcmV?d00001 diff --git a/icon/turtle.png b/icon/turtle.png new file mode 100644 index 0000000000000000000000000000000000000000..e7bfa762803f403b76a469b65a1d17cdcdd04f05 GIT binary patch literal 8745 zcmb_?c~}!?_x72|Bn-hoKo$jrAfh57R-p(ABuIfu5nSqmvb41dB4Pza_8}CctqR&! ztf)i*#h(lK3gSW_(YDrFBnp)l5aR0sXn`mQQ3CwV;QM~p_5J;Q{FAw6o|!q%S?>Ej zXZR*`d4Pa#$p-+z$ANw;0SG)Kfac-P#+~Jx@y8_bqjiarU5U~0JHdao@7kEyn0fI# zw`jXF((vk3_Uh939mzXmwnQhw(xoEb_0G$eIp!iZ zm8IY7Nge;Rdh4<+-HV&j$0|bpdYsz1^knF4Q+|%`|NGDCPr|?Y#Vp{}JXxsTd~IQ5 z#@lb=;>&BsQ;quh{9OuZvAalo(lAOx5d3PRmxqGpt>D@UWuYT8v~Av(dIfL3EDYbQ zpV`VlPHVNg%Q;JAP-i7=^clC_BMS}UMUs+P+O70#ZDiW3UvjPRMgzTiDr0YLkQP z)VP)3ohqW?h$ZLS(8bfz9I05tI#X$w=7KP4lik)%s-CBu$F1jOxoTI^^M9UF{Z1X3 z{OreBSL7$Jfad4PA=}2@RAk1Dy=}}qDjmKtmbTI=J;qsYQMZD zdH7M%8D*e3&_>dNUyTP@m!31o=s5acudbv|NsDVtNyCf|7y00!l#7H&>}->!PgSdf z?4r4md}TQvlyf^dN^{sQX2L$yI?$!c3W-cVLm<5-jm#EXrU|HzH3K|qc4VAUT}fN^ z5H;=Vwc)#dbkrqg@AK8Zx@}uT$i{a&!V+c3$nm6(znADVw`M}O{EU8xORYvaL(72K zWS#ESVIFJ8N_vqtxp9}ia4PGs9h!lRvA11r0OSuYT1$GXvd}lwppHj21}hFu9DAe1 zmO69l0YvtCfu#ChH#bj2siHipz|dm>|2r?BW`pG*7(&qgHsr6786S zFe&KCF={AYtoGDXXZP(Y#`s~e_rNx+(3(OD1Ypj@CT_&j?6qwyhD-QDaAWOYVV7qk`LGlvSw(#&~{sW zJaEIH>ro@6(M^8@xyTbO6(s_n;ieFuN5@mzqzX@FR-6mjBNoLr34DXJC8A0!4$FOI z0v~s!#NB{U8e$k&TLYz?Qqgp6b(c25x4>uSF)Q?Isz|2pYWk5-9^giDvK+K;)6yEt zy&4j92Ze(?{{CEat{WPO&b{2|-In&Q=S(vbbyi&?%A@O&v=`raWXzyiPu{#Q{KFWt z;E+026v)C^-W0{s@8TkM|NW&^oc3DJt$f2eb23O1AX2ZN-)unGS5nZ^;QR7sS=A1w z3+rdo-uS#RgphRU=DlAv?OQCM5~zATiJxX*RgzfNU(=EDa`A;MMj8_G-GkE$$qno?^7*@MXtP0r?sYZ>N0hmd!<)M@|S zk)JYy5O zRd%0h1}^XI92=_HN>^FMlnU3aQ9DY6$!{;66Fv<(7{l(#z5Z=Om5H%?&Zm=g#iRdh zDQa52IL`C?a>^D4LER@&-N+PWDQ@H(u5l|gADJrc_`KAMK9yaZWJDTz4}WA4-hAUM z4JptpQh7^eON8q(9Ue_}wdv`wdph~hkvqeVUFa^L}e)hyyR9b%2)6+kp z&pN->NtF7w&)BQMErH>|njX%RgOSZOof$VUApVvPv}?=F z5i`30wJpjEls zkLuIEACHvAbYvbq8?Yt8dcnJGG2G8^Q|p$zXG^=zo;m_?i!tC&R9}%nAc_S^A`N`gN3aiS|A`Rq6o=R}<*-_|Rx+q*VR3tJwCs*TZ>Y^)Jlu%*qeLpTy#6 znYk_ywm#MaU)V|4LTFR0s?`4O=QFD27{95=cyo?pKx8Ha95d6%L@`ai$9o#QJil+s zEk0n+k9N{Q)R(Zs)+;5^GV2+a*+5Dxb+tw&RCVmIhv+v%c?z?nMvqBo^h)wP42nO% zPh3E%q%t$zHBn&KFD~4y!M;%%Lr^F#(Cg#?xA^&~ZMPOrTL|Lydkv?xmUNwqfF;5o zAka>Q(t`*uKG5!(FpoapsIeExB zo?CzB7T>enQ@!3M)OBamA1j1=c$(6rH_38Nu!b$L;K^4W7$0vv{iNLN69JT=hefbV zxQXjvB z31LWKE;*u|>1j@s?vvvdv%bOA(g=-%Fgm-FWV|!qZR`2qGuC?m&4a&&GIH2aD5``4 zU(^8lq$OIq*V>V)Ua@N>yVIU}RB>xRRk}!`1R45_tG3++x{d8dy&;qo$N%Fs+`h2d zOlr!QP&QDWEI#<Yg81+;`+2eV7q@UaaF~ZGn)CwVfszM_qUS?s(?v%|<{1 zAQ)+*yCK0$1}Dk^R?^YG$}E_~O(zjN8}+kxZJxH2l?-mmuA#5%&C(1YMnj0_Ll_+f zJDM79{&%ZBv#8qLHb!$^i-prr=Ok;qV28$G)vpft3M1eVq8u?PHXse)ZK-{XCcrmz zgIAIvU4{EW*}=vAII3_%S7Y{@Q^0|%!yT#aD6%>SV+EuD9OxyOlUb>6pB0|F6{5#& zTwQ9l>0wdMgEs>KVlih=U+uuXo=)G8L_=HeZDD!YzHR(^Q)Z=xP~2Ra)x#Mg72#3^ zDdrOwK2~#?+iroP3H3p~H1sqUma?@bxlZO=Fl+D*=`ZKVrWZaAbQSy{(ttSFr|a;B z?Pq;ugp7;GU`d}Ey7$B?x7BP<_rJ<^$%aLbY@fSn2EFqeWP!z?p| zg}M+m!Q7y-xOg0l1huc#brp%)*^Lg1?TaA-vm51`VR;=7ezWT)#92BNpO5?$29n;c z1sKPxJyF#l?mY4}?R8K0#CCj9V$&ZcRANH@y?<@L`Zzbf@$;(SCm-Bf^km=WJ*8|Y zxy%;h10YHjK!Lmbm37C;CcPkA&uM-oqHe-3>75*edzvS7V63RJ@6^)wTPM;tZ#j|t zyg34*ca@`3hNn$=_C$Ft8dcPBeo3tZTn!MbQYZbLE#`=gP)oZB_YB=DxhuGSZ7mo&1(*>Hmqtl@)OIwQZcB!Zrc<*2H;Y5`$+(l9=u=M(Qp#b^c&`-=6J z2=cXdoV9Bpr3LHHmQZKmE8Ryw;bRWi{2z@ju}pJ;Eyd|WRJ4;e3{sLts-bjz zJ48*<|EqP{B1;6A3ulBYgwe!rcBqhf6LDp?CeyDoWjYcvoWVg048c6?Qr3y$c`h=GZcEuj zq^xv_Urcg>!Tw5o8MC`I(g^N&894zfcb^y5>m1%^5phc6FRC=920at!M7)pL8r0EG zmB=;rjy-N(%0{Bn@XZBo@okrVfQj1_>>extesKIhm%h0DKX$d_VWf#^A3sorb;j%v@jo@o|Dr|HL@03X&o*nbt9jWf5?5;$UIfAE8;({$#5 zq8etS+@U~me5smVr<{BaHaPLeTc#bV& z5=SBTr(cT$pkS$*i~WfatWb7oHe^SVGS{$14tQCXejzhSgV0$1^xmlUJ-|qQNhAN(uNB) z6c~C7ww*ixQLEW4XlinMwz9|S2~?NKKc|c=Fa(-y6Iv z9^>X)z+rdFTsOy+33`zn#zE_hcvba-r5nsYK$R~3BLca49ju#7xxv*IQn6B52x_EY zHn9~eYUj*9o_koNB3W2cSc+uXC0rPlA10#&%6Ot6Up+vE^1XouX7OGHU(8oxw>ed+ z2(w#9GH%>@3j6r&@!D8rJ}?IgH^j@$FlkXJWZOwF!mmX}pvkW=d0NA+Oi}pM{7;rkWP|6sduz^H> z$e8*6)p?$e;IVl54; zIcb~$BCaS$VE}Ke;%hJAbY$%xLM#LVWhRO`bt!dTg`+z-(<@=F@I1k+P=>Uq2XgDp)11IM z4JsF)YDI-G-W#7;)aQ}e-sTz5R6AC?BIByDlG+YhBm5Y|{ttpG^*3p$~l~ln1)= z6dYNM#4uOcPpAy)CNtSn(;OkGBf0CjOXk}k8f%i}A>Cu6%pDvJ4z7a3rLx3j#lE2& z*1v3`k(g)#^v`~<{s+N8Ejr99K*R#(-G!Qtqhs^d;FgyOtG4&uS0-Wyva5KtX5KAx z=vIf%(R#sjX)#A8s51eolm8yHGDlxVK7t(^M6-#4r7B-0qh1gCFNbDhrAN%!c2?a2 z*!t}4v_wPO{I&MzfjnTcHzG|iT&X#j(5~3U;ati9al`{+Cwap<8peiBH)(0uiXLMX zF?O%W2kcM{{J1{cs0+$7b-e}*s`W=mN0Q}e-Zhm`qs_wo(d zp3Bsk|NDlGsYJO%Ex$92Q^o5J}rS1pftY<3!N6$j+G>B?j=CE$wD)b{%tsk|Rr14)&OKSgM|CT(6`UZOe350g0 z4?ilx7IZO%32E&9_Eak=(ML{nfoe<`wYn3hf~&AH7HCaidEa#k<^oHjt0n|J3qNBK z%|Q|s$&9E@E-f-}sSOo?ZS4h3EMj&)_dS%v)$m}+#5M}PP;;Xk=~A{K=7eO&)<_(&!ZsF}@CIiC(akL`@(l@JY#(URyK#eN z6@*!xCz&Wr#XzF6<5>kU--23$x8mYh)^=>nRt-aUxJjtC#WL;1jlS!#M?d)c???jn zfm%M?QFNV$-BfS*m<^QJX-M&-wkdvmu?^C!^}LjZYF_c)O&nNyzfaM1EMYmD_1J6@ z`4DAFH7*(WR`043AlfI#;XP*}Q7AZwGA#8Wu1N~&)(E80ut;l4 zZ)L;M1*)G2=h9{M_w>b1@4Iv<4ILQBv#}GBO+%`4WP@QI)Cz2q^Fd~ju{C9XqT`!u zP=JGvNhEXB@W7MX`FkNW8-e|Ra;2~;;yc_w_A7euZrim~P|f?z8D@y~VPnU9|I!)2 z048SNZrD3K75YKt4C+wJsmqQj9q}yHvaORGG!DcrYJ#C<>RDgR1x623Y7Ja-zbWJ#-%*!maN57-P`v`s^q~HY(JrC9CrCsj8dpTXA9ML)BDA4A|cB%)OSQ@%ClKJ$7ZN06u_3%)>=XB08vE2ey- zXlEDD$jI%+(9CY6rtIjIn4UKsJQonr$n!LGf5N0(5SCV$v7$H-+x%3bJAELQHEKJ| zUkJ^KJN$^sHS{ue1)C9NSd`u2?24%3S;KethJL+gdBOY;1&t}7J<_UalZ$uY**Y=)y)bn+?DnV!Sz%@fZ04kXvc5DAd9?+Z&g zhfZNjpyJ39)ZY>+UgT?Cy@k$!kl_e}$w73C;xcWEkCeN*dhk(XmJl)=k9AtUoh2AE znMegEj%csKK?0?(B%UnLe%T8R8{4NSYGigWSv+l>gBVQ4k zh=HzN{V{7$3Ds+~gyLI5UGOK08(9vffB)26N;(^AlSTrl%o))0S0+>fxUM~JcxVFr zi2~kQz9JCkLw2Mm-6SRa;i3utS1y3C&nv#aI|PA!ot|-1P6seXm`M`5M4uL<#Tn=mXR1ju}LOD z%<=<;my6LWdsykeyjpd3|-+$9jtJ3he4Z!-~91o&V*o1$$tmp`4jE? z)ZL~~BFgjs(iJno9ttM?GR-VaAEaB*9Evgq)pH9Zwz=?+C4vyE0L3P0f(dLW;9(V? zkINgL4#<>jYk;oh*KsGhfj!blQf!6oB0Vm}4x7aU_3fP4T;^WsyzAZ5-QW!BrRGEN zohw+0YSj4##i}=N{QMNDCA24QwIUR=>FE*qY%dgQkYNfZ)P+zU+x&` zlA;{MIt;0@@QNFXD3LZcM{FQQmWp!x(uT!C-6$*P6Eknpa9%i= zk^A(GKc{kacNtiF>@0nocMm{X@5D-GFMe_{E~>&s{+@0r+d2NeM+o$4@HR$;*v$NhXvk0}qz3)38D z7fi!>Z+qh9`R`NdLCXNCvU0+n_qC0$lhz-EIHgCvN))f4CZ1D{-)hq)gDJ0d!Fl&p z%Q@nw!G0fWe#9r~86$9=7Y5cT?NMlhLfM6bnb(d|{B8=uwAHL3VYKVwX#uQMWgDL9 zyPv(H>bW4zf8mS8U$ouapQSi#DNsn;!1S7Dr#|+4h>;R&R(y_0tck_=;It6M#dR~R zf`e^4S7>5hzFv55kv#>JZP~oABQr>5@YQFg@W4hO{`qKnnL0ra7n*X@v3w(l?@AW0t;CiV@nx`!J%9H70ox?>H9>qCl4 zRUN6=*H7dl4vQ`BP9o8&UK=c^9bIU7pj~uMBMEvw;m$1_d}XV9h@kd;+jW2x8D#+b zu*{{blX<4j0+jlO?5mXw_B@ZaXz%A|xHfnnvjTqICND28E`Aa9=Z9*1CCV|jF?R_M zU4>bh@A=oKZ7rDE`Usk@)f1i#b)J~C?;)^O2wdX(F>7;h=7C@BqY2q1LZ05wCdcd_ zhHQ|gCJ?W`H?`ug)f{EO$t53!2&SWG#+qbJa=(kdQPTefm2D+v literal 0 HcmV?d00001 diff --git a/mine.lua b/mine.lua new file mode 100644 index 0000000..5ce3764 --- /dev/null +++ b/mine.lua @@ -0,0 +1,727 @@ +package.path = "/mod/?.lua;" .. package.path +local PriorityQueue = require "PriorityQueue" + +function Set(list) + local set = {} + for _, l in ipairs(list) do set[l] = true end + return set +end + +local yieldTime = 0 +function yield() + if os.clock() - yieldTime > 2 then + sleep(0) + yieldTime = os.clock() + end +end + +function arr(n, init) + local a = {} + for _ = 1, n do + table.insert(a, init) + end + return a +end +function arr2(x, y, init) + local a = {} + for _ = 1, y do + table.insert(a, arr(x, init)) + end + return a +end + +local dirMap = { + ["0,-1"] = 0, + ["0,1"] = 0.5, + ["1,0"] = 0.25, + ["-1,0"] = -0.25, +} +function direction(v) + local d = dirMap[v.x..","..v.z] + assert(d) + return d +end + +function findDistances(points) + local dist = arr2(#points, #points, math.huge) + -- local prev = arr2(#points, #points) + + for i = 1, #points do + for j = 1, #points do + if i ~= j then + dist[i][j] = (points[i] - points[j]):length() + -- prev[i][j] = i + end + end + end + for i = 1, #points do + dist[i][i] = 0 + -- prev[i][i] = i + end + + return dist +end + +function groupOres(ores, dist, offset) + if not offset then + offset = 0 + end + + local groups = {} + for i, o in ipairs(ores) do + table.insert(groups, { + ["type"] = o.name, + ["blocks"] = { + [i] = vector.new(o.x, o.y, o.z), + }, + }) + end + + local didJoin = true + while didJoin do + didJoin = false + for i, io in pairs(groups) do + for x, a in pairs(io.blocks) do + for j, jo in pairs(groups) do + if i ~= j and jo.type == io.type then + for y, b in pairs(jo.blocks) do + -- yield() + assert(a ~= b) + if dist[offset + x][offset + y] == 1 then + for z, p in pairs(jo.blocks) do + io.blocks[z] = p + end + groups[j] = nil + didJoin = true + break + end + end + end + end + end + end + end + + local retGroups = {} + for _, g in pairs(groups) do + local v = vector.new(0, 0, 0) + local retBlocks = {} + for _, p in pairs(g.blocks) do + v = v + p + table.insert(retBlocks, p) + end + g.blocks = retBlocks + g.center = v / #g.blocks + assert(g.center) + table.insert(retGroups, g) + end + + return retGroups +end + +function pathThrough(points, dist, s, e) + -- local n = #points + + -- dist[s][n] = 0 + -- dist[n][s] = 0 + -- dist[e][n] = 0 + -- dist[n][e] = 0 + + -- for k = 1, #points do + -- for i = 1, #points do + -- for j = 1, #points do + -- if dist[i][j] > dist[i][k] + dist[k][j] then + -- dist[i][j] = dist[i][k] + dist[k][j] + -- prev[i][j] = prev[k][j] + -- end + -- end + -- yield() + -- end + -- end + + -- local path = {e} + -- while s ~= e do + -- e = prev[s][e] + -- table.insert(path, 1, e) + -- end + + -- return path + + -- nearest neighbour + local unvisited = {} + local ui = nil + for i = 1, #points do + if not e or i ~= e then + table.insert(unvisited, i) + end + if i == s then + ui = #unvisited + end + end + assert(ui) + + local visited = {} + local route = {} + while #unvisited ~= 1 do + local u = unvisited[ui] + table.remove(unvisited, ui) + + local cDist = math.huge + local closest = nil + for ii = 1, #unvisited do + local i = unvisited[ii] + assert(i ~= u) + if dist[u][i] < cDist then + cDist = dist[u][i] + closest = ii + end + end + assert(closest) + table.insert(route, unvisited[closest]) + ui = closest + end + if e then + table.insert(route, e) + end + + return route +end + +-- A* +function findPath(s, e) + local points = {} + function addPoint(p) + local k = p:tostring() + if not points[k] then + points[k] = p + end + return k + end + s = addPoint(s) + e = addPoint(e) + + function h(i) + return (points[e] - points[i]):length() + end + + function neighbors(k) + local p = points[k] + local ns = { + p + vector.new( 1, 0, 0), + p + vector.new( 0, 1, 0), + p + vector.new( 0, 0, 1), + p + vector.new(-1, 0, 0), + p + vector.new( 0, -1, 0), + p + vector.new( 0, 0, -1), + } + + for i, n in ipairs(ns) do + ns[i] = addPoint(n) + end + return ns + end + + local gScoreT = {} + gScoreT[s] = 0 + function gScore(i) + if gScoreT[i] then + return gScoreT[i] + else + return math.huge + end + end + + local fScoreT = {} + fScoreT[s] = h(s) + function fScore(i) + if fScoreT[i] then + return fScoreT[i] + else + return math.huge + end + end + + local openSet = PriorityQueue(function(a, b) + return fScore(a) < fScore(b) + end) + openSet:enqueue(s, s) + + local prev = {} + local found = false + while not openSet:empty() do + local current = openSet:dequeue() + if current == e then + found = true + break + end + + local ns = neighbors(current) + for _, n in ipairs(ns) do + tentativeG = gScore(current) + 1 + if tentativeG < gScore(n) then + prev[n] = current + gScoreT[n] = tentativeG + fScoreT[n] = tentativeG + h(n) + if not openSet:contains(n) then + openSet:enqueue(n, n) + end + end + end + end + assert(found) + + local path = {points[e]} + local current = e + while prev[current] do + current = prev[current] + table.insert(path, 1, points[current]) + end + return path +end + +local ORES = Set{ + "minecraft:coal_ore", + "minecraft:deepslate_coal_ore", + "minecraft:iron_ore", + "minecraft:deepslate_iron_ore", + "minecraft:copper_ore", + "minecraft:deepslate_copper_ore", + "minecraft:gold_ore", + "minecraft:deepslate_gold_ore", + "minecraft:redstone_ore", + "minecraft:deepslate_redstone_ore", + "minecraft:emerald_ore", + "minecraft:deepslate_emerald_ore", + "minecraft:lapis_ore", + "minecraft:deepslate_lapis_ore", + "minecraft:diamond_ore", + "minecraft:deepslate_diamond_ore", + + "create:ochrum", + "create:zinc_ore", + "create:deepslate_zinc_ore", + "create_new_age:thorium_ore", + + "powah:deepslate_uraninite_ore_poor", + "powah:deepslate_uraninite_ore", + "powah:deepslate_uraninite_ore_dense", + "powah:uraninite_ore_poor", + "powah:uraninite_ore", + "powah:uraninite_ore_dense", + + -- "minecraft:diamond_ore", + -- "minecraft:netherrack", +} +local BLACKLIST = Set{ + "minecraft:diamond_pickaxe", + "computercraft:wireless_modem_advanced", + "advancedperipherals:geo_scanner", + "enderchests:ender_chest", + "functionalstorage:ender_drawer", + "advancedperipherals:chunk_controller", +} +local FUEL = "minecraft:coal" +local CHANNEL = 1337 + +settings.define("mine.name", { + description = "Miner name", + default = "DiggyBoi", + type = "string", +}) + +function selectItem(item, nbt) + for i = 1, 16 do + info = turtle.getItemDetail(i) + if (not item and not info) or (info and info.name == item and (not nbt or item.nbt == nbt)) then + turtle.select(i) + return i + end + end +end + + +Miner = {} +function Miner.new() + local self = setmetatable({}, { __index = Miner }) + self.name = settings.get("mine.name") + self.equipped = { + ["left"] = { + ["last"] = "NONE", + ["lastNbt"] = nil, + ["fun"] = turtle.equipLeft, + }, + ["right"] = { + ["last"] = "NONE", + ["lastNbt"] = nil, + ["fun"] = turtle.equipRight, + }, + } + + -- Get upgrades to a known state by "equipping" nothing + self:equip(nil, "left") + self:equip(nil, "right") + + self:equip("advancedperipherals:geo_scanner", "right") + self.scanner = peripheral.wrap("right") + + self:equip("computercraft:wireless_modem_advanced", "right") + self.modem = peripheral.wrap("right") + self.modem.open(CHANNEL) + + self.pos = vector.new(0, 0, 0) + self:doGPS(true) + + self:equip("advancedperipherals:chunk_controller", "left") + + self.i = 1 + return self +end + +function Miner:equip(item, side, nbt) + local e = self.equipped[side] + if item == e.last and nbt == e.lastNbt then + return + end + + assert(selectItem(item, nbt)) + e.fun() + e.last = item + e.lastNbt = nbt +end + +function Miner:sendMessage(type, msg) + self:equip("computercraft:wireless_modem_advanced", "right") + msg["type"] = type + msg["name"] = self.name + msg["pos"] = self.absolutePos + self.modem.transmit(CHANNEL, CHANNEL, msg) +end + +function Miner:dig(dir) + self:equip("minecraft:diamond_pickaxe", "right") + if dir == "up" then + assert(turtle.digUp()) + elseif dir == "forward" then + assert(turtle.dig()) + elseif dir == "down" then + assert(turtle.digDown()) + end +end + +function Miner:xchgItems() + local slots = {} + local emptySlots = 0 + for i = 1, 16 do + local info = turtle.getItemDetail(i) + if info then + assert(info.name) + if not BLACKLIST[info.name] then + slots[i] = info + end + else + emptySlots = emptySlots + 1 + end + end + + if emptySlots >= 2 and turtle.getFuelLevel() >= 1000 then + return + end + + if turtle.detectDown() then + self:dig("down") + end + + if emptySlots < 2 then + selectItem("enderchests:ender_chest") + assert(turtle.placeDown()) + + for i, info in pairs(slots) do + assert(turtle.select(i)) + assert(turtle.dropDown()) + end + self:dig("down") + end + + if turtle.getFuelLevel() < 1000 then + selectItem("functionalstorage:ender_drawer") + assert(turtle.placeDown()) + assert(turtle.suckDown()) + assert(turtle.refuel()) + self:dig("down") + end +end + +function Miner:safeMove(dir) + if dir == "up" then + while turtle.detectUp() do + self:dig("up") + end + assert(turtle.up()) + elseif dir == "forward" then + while turtle.detect() do + self:dig("forward") + end + assert(turtle.forward()) + else + if turtle.detectDown() then + self:dig("down") + end + assert(turtle.down()) + end +end + +function Miner:doGPS(orientation) + local x, y, z = gps.locate() + assert(x) + self.absolutePos = vector.new(x, y, z) + + if orientation then + assert(turtle.forward()) + x, y, z = gps.locate() + assert(x) + self.dir = vector.new(x, y, z) - self.absolutePos + assert(turtle.back()) + end +end + +function Miner:findOres(radius) + self:equip("advancedperipherals:geo_scanner", "right") + local info, err = self.scanner.scan(radius) + assert(info, err) + + local found = {} + for _, b in ipairs(info) do + -- only ores and avoid bedrock + if ORES[b.name] and self.absolutePos.y + b.y >= -58 then + table.insert(found, b) + end + end + return found +end + +function Miner:faceDir(newDir) + local deltaDir = direction(newDir) - direction(self.dir) + if deltaDir == 0.25 or deltaDir == -0.75 then + assert(turtle.turnRight()) + self.dir = newDir + elseif deltaDir == -0.25 or deltaDir == 0.75 then + assert(turtle.turnLeft()) + self.dir = newDir + elseif deltaDir == 0.5 or deltaDir == -0.5 then + assert(turtle.turnRight()) + assert(turtle.turnRight()) + self.dir = newDir + elseif deltaDir == 0 then + -- nothing to do :) + else + assert(false, "invalid delta dir "..deltaDir) + end +end + +function Miner:navigateThrough(path) + for _, p in ipairs(path) do + -- print("move from to", self.pos, p) + local delta = p - self.pos + assert(delta:length() ~= 0) + -- print("doing", delta) + if delta:length() ~= 1 then + -- print("path finding between points") + local path = findPath(self.pos, p) + table.remove(path, 1) + table.remove(path, #path) + assert(#path ~= 0) + + self:navigateThrough(path) + delta = p - self.pos + end + assert(delta:length() == 1) + + local moveDir = nil + if delta.y == 1 then + moveDir = "up" + elseif delta.y == -1 then + moveDir = "down" + else + self:faceDir(delta) + moveDir = "forward" + end + + self:safeMove(moveDir) + self.pos = p + self.absolutePos = self.absolutePos + delta + end +end + +function Miner:mineOres(radius) + local startingDir = self.dir + self.pos = vector.new(0, 0, 0) + + local ores = self:findOres(radius) + local orePoints = {} + for _, b in ipairs(ores) do + table.insert(orePoints, vector.new(b.x, b.y, b.z)) + end + local veins = groupOres(ores, findDistances(orePoints)) + print("Found "..#ores.." ores ("..#veins.." veins)") + + local veinsPoints = { + self.pos, + self.dir * radius * 2, + } + for _, v in ipairs(veins) do + table.insert(veinsPoints, v.center) + end + + local veinsPath = pathThrough(veinsPoints, findDistances(veinsPoints), 1, 2) + -- strip out end point + table.remove(veinsPath, #veinsPath) + + local veinsSummary = {} + for _, i in ipairs(veinsPath) do + local v = veins[i - 2] + table.insert(veinsSummary, { + pos = self.absolutePos + v.center, + type = v.type, + count = #v.blocks, + }) + end + self:sendMessage("iterationStart", { + i = self.i, + oreCount = #ores, + veins = veinsSummary, + }) + + for pi, i in ipairs(veinsPath) do + self:xchgItems() + + local vein = veins[i - 2] + local closest = nil + local cDist = math.huge + for _, b in ipairs(vein.blocks) do + local d = (b - self.pos):length() + if d < cDist then + closest = b + cDist = d + end + end + assert(closest) + + local pathToStart = findPath(self.pos, closest) + table.remove(pathToStart, 1) + table.remove(pathToStart, #pathToStart) + + print("Moving to vein of " .. #vein.blocks .. " " .. vein.type .. " " .. cDist .. " blocks away starting at", closest) + self:navigateThrough(pathToStart) + + local veinPoints = {self.pos} + for _, b in ipairs(vein.blocks) do + table.insert(veinPoints, b) + end + + local veinPathI = pathThrough(veinPoints, findDistances(veinPoints), 1) + local veinPath = {} + for _, i in ipairs(veinPathI) do + table.insert(veinPath, veinPoints[i]) + end + + print("Digging through vein (" .. #vein.blocks .. " blocks)") + self:sendMessage("veinStart", { + i = pi, + total = #veins, + oreType = vein.type, + oreCount = #vein.blocks, + }) + self:navigateThrough(veinPath) + end + + self:navigateThrough({veinsPoints[2]}) + self:faceDir(startingDir) + self.i = self.i + 1 +end + +local miner = Miner.new() +while true do + miner:mineOres(16) +end + + + + + + + + + + + +-- test code, please ignore +assert(false) + +-- local f, err = fs.open("points.csv", "w") +-- assert(f, err) + +local points = { + vector.new(0, 0, 0), + vector.new(0, 0, -16), +} +for _, b in ipairs(ores) do + -- print("found " .. b.name .. " at " .. b.x .. ", " .. b.y .. ", " .. b.z) + table.insert(points, vector.new(b.x, b.y, b.z)) +end +print("found "..#ores.." ores") + +local dist = findDistances(points) +local groups = groupOres(ores, dist, 2) + +for _, g in ipairs(groups) do + print("group of "..#g.blocks.." "..g.type.." at", g.center) +end +print(#groups, "groups of ore found") + +local gPoints = { + vector.new(0, 0, 0), + vector.new(0, 0, -16), +} +for _, g in ipairs(groups) do + table.insert(gPoints, g.center) +end + +local gDist = findDistances(gPoints) +local gPath = pathThrough(gPoints, gDist, 1, 2) +for _, i in ipairs(gPath) do + local p = gPoints[i] + f.write(p.x..","..p.y..","..p.z.."\n") +end + +f.write("MARK\n") + +-- print(points[1], gPoints[gPath[1]]) +-- local pathTo = findPath(points[1], gPoints[gPath[1]]) +-- for _, p in ipairs(pathTo) do +-- -- local p = pathTo[i] +-- -- print(p) +-- f.write(p.x..","..p.y..","..p.z.."\n") +-- end + +miner:mineOres(groups) + +-- table.remove(pathTo, 1) +-- table.remove(pathTo, #pathTo) +-- miner:navigateThrough(pathTo) + +-- f.write("MARK\n") + +-- local allPath = pathThrough(points, dist, 1, 2) +-- for _, i in ipairs(allPath) do +-- local p = points[i] +-- -- print(points[i]) +-- f.write(p.x..","..p.y..","..p.z.."\n") +-- end + +f.close() + +-- local f = vector.new(1, 0, 0) +-- local p = vector.new(0, -1, 7) +-- local t = vector.new(-1, -1, 7) + +-- print(direction(t - p) - direction(f)) diff --git a/mineMonitor.lua b/mineMonitor.lua new file mode 100644 index 0000000..37e347d --- /dev/null +++ b/mineMonitor.lua @@ -0,0 +1,185 @@ +local CHANNEL = 1337 +local TARGET = "devplayer0" +local ICON_BASE = "https://p.nul.ie/cc/icon/" +local ORE_ICONS = { + ["minecraft:coal_ore"] = "coal", + ["minecraft:deepslate_coal_ore"] = "ds-coal", + ["minecraft:iron_ore"] = "iron", + ["minecraft:deepslate_iron_ore"] = "ds-iron", + ["minecraft:copper_ore"] = "copper", + ["minecraft:deepslate_copper_ore"] = "ds-copper", + ["minecraft:gold_ore"] = "gold", + ["minecraft:deepslate_gold_ore"] = "ds-gold", + ["minecraft:redstone_ore"] = "redstone", + ["minecraft:deepslate_redstone_ore"] = "ds-redstone", + ["minecraft:emerald_ore"] = "emerald", + ["minecraft:deepslate_emerald_ore"] = "ds-emerald", + ["minecraft:lapis_ore"] = "lapis", + ["minecraft:deepslate_lapis_ore"] = "ds-lapis", + ["minecraft:diamond_ore"] = "diamond", + ["minecraft:deepslate_diamond_ore"] = "ds-diamond", + + -- ["create:ochrum"] =, + -- ["create:zinc_ore"] =, + -- ["create:deepslate_zinc_ore"] =, + -- ["create_new_age:thorium_ore"] =, + + -- ["powah:deepslate_uraninite_ore_poor"] =, + -- ["powah:deepslate_uraninite_ore"] =, + -- ["powah:deepslate_uraninite_ore_dense"] =, + -- ["powah:uraninite_ore_poor"] =, + -- ["powah:uraninite_ore"] =, + -- ["powah:uraninite_ore_dense"] =, +} + +function oreIcon(t) + local i = "generic" + if ORE_ICONS[t] then + i = ORE_ICONS[t] + end + + return ICON_BASE .. "ore-" .. i .. ".png" +end + +local modem = peripheral.find("modem") +-- local monitor = peripheral.find("monitor") +local chat = peripheral.find("chatBox") +local cartographer = peripheral.find("cartographer") + +function vecToStr(v) + return v.x .. "," .. v.y .. "," .. v.z +end + +function markerSet(msg) + return "autominer_" .. msg.name +end + +function setPosMarker(msg) + local id = markerSet(msg) + local mId = id .. "_pos" + cartographer.removeMarker(id, mId) + cartographer.addPOIMarker( + id, mId, msg.name, msg.name .. "'s position", + msg.pos.x, msg.pos.y, msg.pos.z, + ICON_BASE .. "turtle.png") +end + +function handleStart(msg) + local cMsg = { + {text = msg.name, color = "green"}, + {text = " @ ", color = "white"}, + {text = vecToStr(msg.pos), color = "aqua"}, + {text = " found ", color = "white"}, + {text = tostring(msg.oreCount), color = "red"}, + {text = " ores (", color = "white"}, + {text = tostring(#msg.veins), color = "red"}, + {text = " veins) on iteration ", color = "white"}, + {text = tostring(msg.i), color = "green"}, + {text = "!", color = "white"}, + } + local msgJSON = textutils.serializeJSON(cMsg) + chat.sendFormattedMessage(msgJSON, "AutoMine") + + local id = markerSet(msg) + cartographer.addMarkerSet(id, "AutoMiner " .. msg.name) + cartographer.clearMarkerSet(id) + + setPosMarker(msg) + + local orePoints = {} + for i, v in ipairs(msg.veins) do + table.insert(orePoints, v.pos) + cartographer.addPOIMarker( + id, id .. "_vein_" .. i, v.count .. " " .. v.type, "Vein of " .. v.count .. " " .. v.type, + v.pos.x, v.pos.y, v.pos.z, + oreIcon(v.type)) + end + + cartographer.addLineMarker( + id, id .. "_vein_path", "Mining path #" .. msg.i, "Current mining path", + "#FF00FF", 0.7, 3, + orePoints) +end + +function handleVein(msg) + local cMsg = { + {text = msg.name, color = "green"}, + {text = " @ ", color = "white"}, + {text = vecToStr(msg.pos), color = "aqua"}, + {text = " is mining ", color = "white"}, + {text = tostring(msg.oreCount), color = "red"}, + {text = " ", color = "white"}, + {text = msg.oreType, color = "dark_purple"}, + {text = " (vein ", color = "white"}, + {text = tostring(msg.i), color = "red"}, + {text = " / ", color = "white"}, + {text = tostring(msg.total), color = "red"}, + {text = ")!", color = "white"}, + } + local msgJSON = textutils.serializeJSON(cMsg) + chat.sendFormattedMessageToPlayer(msgJSON, TARGET, "AutoMine") + + local id = markerSet(msg) + setPosMarker(msg) + if msg.i ~= 1 then + cartographer.removeMarker(id, id .. "_vein_" .. (msg.i - 1)) + end +end + +cartographer.refreshIntegrations() + +modem.open(CHANNEL) + +-- handleStart({ +-- i = 69, +-- oreCount = 1337, +-- veins = { +-- { +-- pos = {x = 297, y = 124, z = 1935}, +-- type = "minecraft:coal_ore", +-- count = 12, +-- }, +-- { +-- pos = {x = 297, y = 134, z = 1935}, +-- type = "minecraft:iron_ore", +-- count = 7, +-- }, +-- { +-- pos = {x = 400, y = 134, z = 1935}, +-- type = "minecraft:diamond_ore", +-- count = 2, +-- }, +-- { +-- pos = {x = 400, y = 134, z = 1975}, +-- type = "minecraft:sussy_ore", +-- count = 7, +-- } +-- }, +-- name = "test", +-- pos = {x = 297, y = 154, z = 1935}, +-- }) +-- handleVein({ +-- i = 2, +-- total = 69, +-- oreCount = 1337, +-- oreType = "minecraft:yeet", +-- name = "test", +-- pos = {x = 1, y = 2, z = 3}, +-- }) +-- assert(false) + +while true do + local event, side, channel, replyChannel, msg, distance = os.pullEvent("modem_message") + if channel == CHANNEL then + if msg.type == "iterationStart" then + handleStart(msg) + -- sendChat(msg.name.." found "..msg.oreCount.." ores ("..msg.veinCount.." veins)") + -- for _, v in ipairs(msg.path) do + -- print("vein path "..v.x..", "..v.y..", "..v.z) + -- end + elseif msg.type == "veinStart" then + handleVein(msg) + -- sendChat(msg.name.." is mining "..msg.count.." "..msg.oreType.." (vein "..msg.i..") @ "..msg.pos.x..", "..msg.pos.y..", "..msg.pos.z) + end + end +end diff --git a/tree.lua b/tree.lua new file mode 100644 index 0000000..daf29aa --- /dev/null +++ b/tree.lua @@ -0,0 +1,134 @@ +local dirt = "minecraft:dirt" +local sapling = "minecraft:oak_sapling" +local meal = "minecraft:bone_meal" +local log = "minecraft:oak_log" +local apple = "minecraft:apple" +local stick = "minecraft:stick" +local items = { + sapling, meal, log, apple, stick +} + +local mealCount = 16 + +function selectItem(item) + for i = 1, 16 do + info = turtle.getItemDetail(i) + if info and info.name == item then + turtle.select(i) + return i + end + end +end + +Farmer = {} +function Farmer:new(invName) + local t = setmetatable({}, { __index = Farmer }) + t.invName = invName + return t +end + +function Farmer:connectInv() + local m = peripheral.find("modem") + self.mName= m.getNameLocal() + self.inv = peripheral.wrap(self.invName) +end + +function Farmer:unload(item) + for i = 1, 16 do + info = turtle.getItemDetail(i) + if info and info.name == item then + -- print(item, self.mName, i) + self.inv.pullItems(self.mName, i) + sleep(0.5) + end + end +end + +function Farmer:yoink(item, count) + for i, info in pairs(self.inv.list()) do + if info.name == item then + if info.count >= count then + self.inv.pushItems(self.mName, i, count) + sleep(0.5) + return true + end + end + end + + return false +end + +function Farmer:farmTree(noMeal) + assert(turtle.turnRight()) + assert(turtle.turnRight()) + assert(turtle.forward()) + assert(turtle.forward()) + assert(turtle.down()) + + assert(selectItem(dirt)) + assert(turtle.place()) + assert(turtle.up()) + assert(selectItem(sapling)) + assert(turtle.place()) + + if noMeal then + while true do + local present, info = turtle.inspect() + assert(present) + if info.name == log then + break + end + sleep(20) + end + else + assert(selectItem(meal)) + local grown = false + for i = 1, mealCount do + turtle.place() + sleep(1) + local present, info = turtle.inspect() + assert(present) + if info.name == log then + grown = true + break + end + end + if not grown then + assert(false, "failed to grow tree") + end + end + + turtle.select(1) + assert(turtle.dig()) + assert(turtle.down()) + assert(turtle.dig()) + assert(turtle.up()) + sleep(5) + assert(turtle.down()) + for i = 1, 8 do + sleep(0.5) + turtle.suck() + end + + assert(turtle.up()) + assert(turtle.turnRight()) + assert(turtle.turnRight()) + assert(turtle.forward()) + assert(turtle.forward()) + sleep(0.5) +end + +function Farmer:xchgItems() + self:connectInv() + for _, i in pairs(items) do + self:unload(i) + end + assert(self:yoink(sapling, 1)) + return self:yoink(meal, mealCount) +end + +local f = Farmer:new("ae2:interface_0") +while true do + local noMeal = not f:xchgItems() + f:farmTree(noMeal) +end