-- basic movement module -- for a turtle with a pickaxe, that doesn't care about plowing thru stuff local pretty = require("cc.pretty") local mv = {} -- globals :3 local position = vector.new(0,0,0) local facing = vector.new(1,0,0) -- "east" local itemSlots = {} -- function mv.panic(msg) http.post("https://ntfy.sh/cortan122-cc-panic", msg, { Title = string.format("turtle \u{2116}%d is panicking", os.getComputerID()), Tags = "yellow_square, exclamation" }) term.setTextColor(colors.pink) write(msg) term.setTextColor(colors.white) read() end local function startsWith(haystack, needle) return haystack:sub(1, needle:len()) == needle end -- local function isBlockIdSafe(name) if startsWith(name, "computercraft:") then return false end if name:find("diamond") then return false end if name:find("chest") then return false end if name:find("spawner") then return false end return true end local function safeDig(dig, inspect) local success, data = inspect() if not success then return end if not isBlockIdSafe(data.name) then print(data.name) mv.panic("trying to dig an unsafe block\npress any key to dig anyway...") end dig() end function mv.dig() return safeDig(turtle.dig, turtle.inspect) end function mv.digUp() return safeDig(turtle.digUp, turtle.inspectUp) end function mv.digDown() return safeDig(turtle.digDown, turtle.inspectDown) end function mv.up() position.y = position.y+1 while not turtle.up() do mv.digUp() end end function mv.down() position.y = position.y-1 while not turtle.down() do mv.digDown() end end function mv.forward() position = position + facing while not turtle.forward() do mv.dig() end end function mv.back() position = position - facing assert(turtle.back()) end function mv.turnLeft() turtle.turnLeft() facing.x,facing.z = facing.z,-facing.x end function mv.turnRight() turtle.turnRight() facing.x,facing.z = -facing.z,facing.x end function mv.moveLeft(forward) mv.turnLeft() forward() mv.turnRight() end function mv.moveRight(forward) mv.turnRight() forward() mv.turnLeft() end function mv.isInventoryFull() for i=1,16 do if turtle.getItemDetail(i) == nil then return false end end return true end function mv.dumpInventory(from_slot) from_slot = from_slot or 1 local success, data = turtle.inspect() if not (success and data.name:find("chest")) then mv.panic("no chest to drop stuff off") end for i=from_slot,16 do turtle.select(i) while true do local res, err = turtle.drop() if res or err == "No items to drop" then break end mv.panic(err) end end end local function isItem(slot, name) if slot == nil then return false end local res = turtle.getItemDetail(slot) if res then if name:find(":") then return res.name == name else return res.name:find(name) end end return false end function mv.findItem(name) if isItem(itemSlots[name], name) then return itemSlots[name] end itemSlots[name] = 1 while not isItem(itemSlots[name], name) do if itemSlots[name] == 16 then term.setTextColor(colors.red) print("Press any key to resume, or terminate the program...") mv.panic(string.format("no %s found", name)) print(string.format("trying to find %s again", name)) itemSlots[name] = 0 end itemSlots[name] = itemSlots[name]+1 end return itemSlots[name] end function mv.placeItem(name, place) mv.findItem(name) turtle.select(itemSlots[name]) place() end function mv.turnAround() mv.turnRight() mv.turnRight() end function mv.placeBehind(name) mv.turnAround() mv.placeItem(name, turtle.place) mv.turnAround() end function mv.nTimes(n, func) for i=1,n do func() end end function mv.face(x, z) -- todo: assert valid direction if x ~= 0 and facing.x == 0 then if facing.z == x then mv.turnLeft() else mv.turnRight() end end if facing.x ~= x and x ~= 0 then mv.turnAround() end if z ~= 0 and facing.z == 0 then if facing.x ~= z then mv.turnLeft() else mv.turnRight() end end if facing.z ~= z and z ~= 0 then mv.turnAround() end end local function goBackY(y_delta) if y_delta < 0 then mv.nTimes(-y_delta, mv.down) else mv.nTimes(y_delta, mv.up) end end local function goBackX(x_delta) if x_delta == 0 then return end local sign = 1 if x_delta < 0 then sign = -1 end mv.face(sign, 0) mv.nTimes(x_delta*sign, mv.forward) end local function goBackZ(z_delta) if z_delta == 0 then return end local sign = 1 if z_delta < 0 then sign = -1 end mv.face(0, sign) mv.nTimes(z_delta*sign, mv.forward) end function mv.goBackTo(x, y, z) local x_delta = x - position.x local y_delta = y - position.y local z_delta = z - position.z goBackY(y_delta) if facing.x == 0 then goBackZ(z_delta) goBackX(x_delta) else goBackX(x_delta) goBackZ(z_delta) end end function mv.inspectAt(vec) local delta = vec - position local dist = math.abs(delta.x) + math.abs(delta.y) + math.abs(delta.z) assert(dist == 1, "vector not adjacent") if delta == vector.new(0,1,0) then return turtle.inspectUp() elseif delta == vector.new(0,-1,0) then return turtle.inspectDown() elseif delta.y == 0 then mv.face(delta.x, delta.z) return turtle.inspect() end assert(false, "unreachable") end function mv.attemptMoveTo(vec) local delta = vec - position local dist = math.abs(delta.x) + math.abs(delta.y) + math.abs(delta.z) assert(dist == 1, "vector not adjacent") local res if delta == vector.new(0,1,0) then res = turtle.up() elseif delta == vector.new(0,-1,0) then res = turtle.down() elseif delta.y == 0 then mv.face(delta.x, delta.z) res = turtle.forward() end if res then position = vec end return res end function mv.getPosition() return vector.new(position.x, position.y, position.z), vector.new(facing.x, 0, facing.z) end local saved_position = table.pack(mv.getPosition()) function mv.save() saved_position = table.pack(mv.getPosition()) end function mv.restore() local pos,face = table.unpack(saved_position) mv.goBackTo(pos.x, pos.y, pos.z) mv.face(face.x, face.z) end return mv