1
0
mirror of https://github.com/kepler155c/opus synced 2024-11-15 05:04:50 +00:00
opus/sys/init/6.tl3.lua

1274 lines
29 KiB
Lua
Raw Normal View History

2017-10-28 00:24:48 +00:00
if not _G.turtle then
2018-01-24 22:39:38 +00:00
return
2016-12-11 19:24:52 +00:00
end
local Pathing = require('opus.pathfind')
local Point = require('opus.point')
local synchronized = require('opus.sync').sync
local Util = require('opus.util')
2017-10-28 00:24:48 +00:00
local os = _G.os
local peripheral = _G.peripheral
local turtle = _G.turtle
2016-12-11 19:24:52 +00:00
local function noop() end
2017-10-28 00:24:48 +00:00
local headings = Point.headings
2017-11-15 05:08:42 +00:00
local state = { }
2016-12-11 19:24:52 +00:00
2017-09-15 05:08:04 +00:00
turtle.pathfind = Pathing.pathfind
2016-12-11 19:24:52 +00:00
turtle.point = { x = 0, y = 0, z = 0, heading = 0 }
2017-10-28 00:24:48 +00:00
function turtle.getState() return state end
function turtle.isAborted() return state.abort end
function turtle.getStatus() return state.status end
function turtle.setStatus(s) state.status = s end
2016-12-11 19:24:52 +00:00
2017-07-24 02:37:07 +00:00
local function _defaultMove(action)
2018-01-24 22:39:38 +00:00
while not action.move() do
if not state.digPolicy(action) and not state.attackPolicy(action) then
return false
end
end
return true
2016-12-11 19:24:52 +00:00
end
2019-01-18 04:33:19 +00:00
function turtle.getPoint() return turtle.point end
2017-07-24 02:37:07 +00:00
function turtle.setPoint(pt, isGPS)
2018-01-24 22:39:38 +00:00
turtle.point.x = pt.x
turtle.point.y = pt.y
turtle.point.z = pt.z
if pt.heading then
turtle.point.heading = pt.heading
end
turtle.point.gps = isGPS
return true
2017-07-24 02:37:07 +00:00
end
function turtle.resetState()
2018-01-24 22:39:38 +00:00
state.abort = false
state.status = 'idle'
state.attackPolicy = noop
state.digPolicy = noop
state.movePolicy = _defaultMove
state.moveCallback = noop
2019-04-25 02:09:36 +00:00
state.blacklist = nil
2019-06-18 19:19:24 +00:00
state.reference = nil -- gps reference when converting to relative coords
2018-01-24 22:39:38 +00:00
Pathing.reset()
return true
2016-12-11 19:24:52 +00:00
end
function turtle.reset()
2018-01-24 22:39:38 +00:00
turtle.point.x = 0
turtle.point.y = 0
turtle.point.z = 0
turtle.point.heading = 0 -- should be facing
turtle.point.gps = false
2016-12-11 19:24:52 +00:00
2018-01-24 22:39:38 +00:00
turtle.resetState()
return true
2017-05-24 23:48:48 +00:00
end
2019-01-13 18:24:37 +00:00
local function _dig(name, inspect, dig)
if name then
local s, b = inspect()
if not s or b.name ~= name then
return false
end
end
return dig()
end
function turtle.dig(s)
return _dig(s, turtle.inspect, turtle.native.dig)
end
function turtle.digUp(s)
return _dig(s, turtle.inspectUp, turtle.native.digUp)
end
function turtle.digDown(s)
return _dig(s, turtle.inspectDown, turtle.native.digDown)
end
2016-12-11 19:24:52 +00:00
local actions = {
2018-01-24 22:39:38 +00:00
up = {
detect = turtle.native.detectUp,
2019-01-13 18:24:37 +00:00
dig = turtle.digUp,
2018-01-24 22:39:38 +00:00
move = turtle.native.up,
attack = turtle.native.attackUp,
place = turtle.native.placeUp,
drop = turtle.native.dropUp,
suck = turtle.native.suckUp,
compare = turtle.native.compareUp,
inspect = turtle.native.inspectUp,
side = 'top'
},
down = {
detect = turtle.native.detectDown,
2019-01-13 18:24:37 +00:00
dig = turtle.digDown,
2018-01-24 22:39:38 +00:00
move = turtle.native.down,
attack = turtle.native.attackDown,
place = turtle.native.placeDown,
drop = turtle.native.dropDown,
suck = turtle.native.suckDown,
compare = turtle.native.compareDown,
inspect = turtle.native.inspectDown,
side = 'bottom'
},
forward = {
detect = turtle.native.detect,
2019-01-13 18:24:37 +00:00
dig = turtle.dig,
2018-01-24 22:39:38 +00:00
move = turtle.native.forward,
attack = turtle.native.attack,
place = turtle.native.place,
drop = turtle.native.drop,
suck = turtle.native.suck,
compare = turtle.native.compare,
inspect = turtle.native.inspect,
side = 'front'
},
back = {
detect = noop,
dig = noop,
move = turtle.native.back,
attack = noop,
place = noop,
suck = noop,
compare = noop,
side = 'back'
},
2016-12-11 19:24:52 +00:00
}
function turtle.getAction(direction)
2018-01-24 22:39:38 +00:00
return actions[direction]
2016-12-11 19:24:52 +00:00
end
function turtle.getHeadingInfo(heading)
2018-01-24 22:39:38 +00:00
heading = heading or turtle.point.heading
return headings[heading]
2016-12-11 19:24:52 +00:00
end
2019-01-18 04:33:19 +00:00
function turtle.isTurtleAtSide(side)
local sideType = peripheral.getType(side)
return sideType and sideType == 'turtle'
2018-03-21 17:42:29 +00:00
end
2019-01-17 18:31:05 +00:00
-- [[ Policies ]] --
turtle.policies = { }
function turtle.addPolicy(name, policy)
turtle.policies[name] = policy
end
function turtle.getPolicy(policy)
if type(policy) == 'function' then
return policy
end
local p = turtle.policies[policy]
if not p then
error('Invalid policy: ' .. tostring(policy))
end
return p
end
2016-12-11 19:24:52 +00:00
-- [[ Basic turtle actions ]] --
local function inventoryAction(fn, name, qty)
2018-01-24 22:39:38 +00:00
local slots = turtle.getFilledSlots()
local s
for _,slot in pairs(slots) do
if slot.key == name or slot.name == name then
turtle.native.select(slot.index)
if not qty then
s = fn()
else
s = fn(math.min(qty, slot.count))
qty = qty - slot.count
if qty < 0 then
break
end
end
end
end
if not s then
return false, 'No items found'
end
return s
end
2017-11-15 05:08:42 +00:00
-- [[ Attack ]] --
2016-12-11 19:24:52 +00:00
local function _attack(action)
2018-01-24 22:39:38 +00:00
if action.attack() then
repeat until not action.attack()
return true
end
return false
2016-12-11 19:24:52 +00:00
end
function turtle.attack() return _attack(actions.forward) end
function turtle.attackUp() return _attack(actions.up) end
function turtle.attackDown() return _attack(actions.down) end
2019-01-17 18:31:05 +00:00
turtle.addPolicy('attackNone', noop)
turtle.addPolicy('attack', function(action)
return _attack(action)
end)
2017-11-15 05:08:42 +00:00
function turtle.setAttackPolicy(policy) state.attackPolicy = policy end
-- [[ Place ]] --
2016-12-11 19:24:52 +00:00
local function _place(action, indexOrId)
2018-01-24 22:39:38 +00:00
local slot
if indexOrId then
slot = turtle.getSlot(indexOrId)
if not slot then
return false, 'No items to place'
end
end
2019-01-18 04:33:19 +00:00
if slot and slot.count == 0 then
2018-01-24 22:39:38 +00:00
return false, 'No items to place'
end
return Util.tryTimes(3, function()
if slot then
turtle.select(slot.index)
end
local result = { action.place() }
if result[1] then
return true
end
if not state.digPolicy(action) then
state.attackPolicy(action)
end
return table.unpack(result)
2018-01-24 22:39:38 +00:00
end)
2016-12-11 19:24:52 +00:00
end
function turtle.place(slot) return _place(actions.forward, slot) end
function turtle.placeUp(slot) return _place(actions.up, slot) end
function turtle.placeDown(slot) return _place(actions.down, slot) end
2019-01-17 18:31:05 +00:00
-- [[ Drop ]] --
local function _drop(action, qtyOrName, qty)
2018-01-24 22:39:38 +00:00
if not qtyOrName or type(qtyOrName) == 'number' then
return action.drop(qtyOrName or 64)
end
return inventoryAction(action.drop, qtyOrName, qty)
2016-12-11 19:24:52 +00:00
end
function turtle.drop(count, slot) return _drop(actions.forward, count, slot) end
function turtle.dropUp(count, slot) return _drop(actions.up, count, slot) end
function turtle.dropDown(count, slot) return _drop(actions.down, count, slot) end
2019-01-17 18:31:05 +00:00
-- [[ Dig ]] --
turtle.addPolicy('digNone', noop)
turtle.addPolicy('dig', function(action)
return action.dig()
end)
turtle.addPolicy('turtleSafe', function(action)
if action.side == 'back' then
return false
end
if not turtle.isTurtleAtSide(action.side) then
return action.dig()
end
return Util.tryTimes(6, function()
os.sleep(.25)
if not action.detect() then
return true
end
end)
end)
2019-04-25 02:09:36 +00:00
local function isBlacklisted(b)
if b and state.blacklist then
2019-04-25 18:44:36 +00:00
for _, v in pairs(state.blacklist) do
2019-04-25 02:09:36 +00:00
if b.name:find(v) then
return true
end
end
end
end
turtle.addPolicy('blacklist', function(action)
if action.side == 'back' then
return false
end
local s, m = action.inspect()
if not isBlacklisted(s and m) then
return action.dig()
end
if s and m and m.name:find('turtle') then
return Util.tryTimes(math.random(3, 6), function()
os.sleep(.25)
if not action.detect() then
return true
end
end)
end
end)
2019-01-17 18:31:05 +00:00
turtle.addPolicy('digAndDrop', function(action)
if action.detect() then
local slots = turtle.getInventory()
if action.dig() then
turtle.reconcileInventory(slots)
return true
end
end
return false
end)
function turtle.setDigPolicy(policy) state.digPolicy = policy end
-- [[ Move ]] --
turtle.addPolicy('moveNone', noop)
turtle.addPolicy('moveDefault', _defaultMove)
turtle.addPolicy('moveAssured', function(action)
if not _defaultMove(action) then
if action.side == 'back' then
return false
end
local oldStatus = state.status
print('assured move: stuck')
state.status = 'stuck'
repeat
os.sleep(1)
until _defaultMove(action)
state.status = oldStatus
end
return true
end)
function turtle.setMoveCallback(cb) state.moveCallback = cb end
function turtle.clearMoveCallback() state.moveCallback = noop end
function turtle.getMoveCallback() return state.moveCallback end
2019-01-18 04:33:19 +00:00
-- convenience method for setting multiple values
2019-01-17 18:31:05 +00:00
function turtle.set(args)
for k,v in pairs(args) do
2018-01-24 22:39:38 +00:00
2019-01-17 18:31:05 +00:00
if k == 'attackPolicy' then
turtle.setAttackPolicy(turtle.getPolicy(v))
2018-01-24 22:39:38 +00:00
2019-01-17 18:31:05 +00:00
elseif k == 'digPolicy' then
turtle.setDigPolicy(turtle.getPolicy(v))
2016-12-11 19:24:52 +00:00
2019-01-17 18:31:05 +00:00
elseif k == 'movePolicy' then
2019-06-18 19:19:24 +00:00
state.movePolicy = turtle.getPolicy(v)
2016-12-11 19:24:52 +00:00
2019-01-17 18:31:05 +00:00
elseif k == 'movementStrategy' then
turtle.setMovementStrategy(v)
2016-12-11 19:24:52 +00:00
2019-01-17 18:31:05 +00:00
elseif k == 'pathingBox' then
turtle.setPathingBox(v)
2016-12-11 19:24:52 +00:00
2019-01-17 18:31:05 +00:00
elseif k == 'point' then
turtle.setPoint(v)
2016-12-11 19:24:52 +00:00
2019-01-17 18:31:05 +00:00
elseif k == 'moveCallback' then
turtle.setMoveCallback(v)
2019-02-21 07:03:41 +00:00
elseif k == 'status' then
turtle.setStatus(v)
2019-04-25 02:09:36 +00:00
elseif k == 'blacklist' then
state.blacklist = v
2019-06-18 19:19:24 +00:00
elseif k == 'reference' then
state.reference = v
2019-01-17 18:31:05 +00:00
else
error('Invalid turle.set: ' .. tostring(k))
2018-01-24 22:39:38 +00:00
end
end
2016-12-11 19:24:52 +00:00
end
2019-01-18 04:33:19 +00:00
-- [[ Fuel ]] --
if type(turtle.getFuelLevel()) ~= 'number' then
-- Support unlimited fuel
function turtle.getFuelLevel()
2019-01-20 03:05:05 +00:00
return 100000
2019-01-18 04:33:19 +00:00
end
end
-- override to optionally specify a fuel
function turtle.refuel(qtyOrName, qty)
if not qtyOrName or type(qtyOrName) == 'number' then
return turtle.native.refuel(qtyOrName or 64)
end
return inventoryAction(turtle.native.refuel, qtyOrName, qty or 64)
end
2016-12-11 19:24:52 +00:00
-- [[ Heading ]] --
function turtle.getHeading()
2018-01-24 22:39:38 +00:00
return turtle.point.heading
2016-12-11 19:24:52 +00:00
end
function turtle.turnRight()
2018-01-24 22:39:38 +00:00
turtle.setHeading((turtle.point.heading + 1) % 4)
return turtle.point
2016-12-11 19:24:52 +00:00
end
function turtle.turnLeft()
2018-01-24 22:39:38 +00:00
turtle.setHeading((turtle.point.heading - 1) % 4)
return turtle.point
2016-12-11 19:24:52 +00:00
end
function turtle.turnAround()
2018-01-24 22:39:38 +00:00
turtle.setHeading((turtle.point.heading + 2) % 4)
return turtle.point
2016-12-11 19:24:52 +00:00
end
function turtle.setHeading(heading)
2018-01-24 22:39:38 +00:00
if not heading then
return false, 'Invalid heading'
end
2019-06-18 19:19:24 +00:00
if heading == turtle.point.heading then
return turtle.point
end
2018-01-24 22:39:38 +00:00
local fi = Point.facings[heading]
if not fi then
return false, 'Invalid heading'
end
heading = fi.heading % 4
if heading ~= turtle.point.heading then
while heading < turtle.point.heading do
heading = heading + 4
end
if heading - turtle.point.heading == 3 then
turtle.native.turnLeft()
turtle.point.heading = (turtle.point.heading - 1) % 4
state.moveCallback('turn', turtle.point)
else
local turns = heading - turtle.point.heading
while turns > 0 do
turns = turns - 1
turtle.native.turnRight()
turtle.point.heading = (turtle.point.heading + 1) % 4
state.moveCallback('turn', turtle.point)
end
end
end
return turtle.point
2016-12-11 19:24:52 +00:00
end
function turtle.headTowardsX(dx)
2018-01-24 22:39:38 +00:00
if turtle.point.x ~= dx then
if turtle.point.x > dx then
turtle.setHeading(2)
else
turtle.setHeading(0)
end
end
2016-12-11 19:24:52 +00:00
end
function turtle.headTowardsZ(dz)
2018-01-24 22:39:38 +00:00
if turtle.point.z ~= dz then
if turtle.point.z > dz then
turtle.setHeading(3)
else
turtle.setHeading(1)
end
end
2016-12-11 19:24:52 +00:00
end
function turtle.headTowards(pt)
2018-01-24 22:39:38 +00:00
local xd = math.abs(turtle.point.x - pt.x)
local zd = math.abs(turtle.point.z - pt.z)
if xd > zd then
turtle.headTowardsX(pt.x)
else
turtle.headTowardsZ(pt.z)
end
2016-12-11 19:24:52 +00:00
end
-- [[ move ]] --
function turtle.up()
2018-01-24 22:39:38 +00:00
if state.movePolicy(actions.up) then
turtle.point.y = turtle.point.y + 1
state.moveCallback('up', turtle.point)
return true, turtle.point
end
2016-12-11 19:24:52 +00:00
end
function turtle.down()
2018-01-24 22:39:38 +00:00
if state.movePolicy(actions.down) then
turtle.point.y = turtle.point.y - 1
state.moveCallback('down', turtle.point)
return true, turtle.point
end
2016-12-11 19:24:52 +00:00
end
function turtle.forward()
2018-01-24 22:39:38 +00:00
if state.movePolicy(actions.forward) then
turtle.point.x = turtle.point.x + headings[turtle.point.heading].xd
turtle.point.z = turtle.point.z + headings[turtle.point.heading].zd
state.moveCallback('forward', turtle.point)
return true, turtle.point
end
2016-12-11 19:24:52 +00:00
end
function turtle.back()
2018-01-24 22:39:38 +00:00
if state.movePolicy(actions.back) then
turtle.point.x = turtle.point.x - headings[turtle.point.heading].xd
turtle.point.z = turtle.point.z - headings[turtle.point.heading].zd
state.moveCallback('back', turtle.point)
return true, turtle.point
end
2016-12-11 19:24:52 +00:00
end
2017-11-15 05:08:42 +00:00
local function moveTowardsX(dx)
2018-10-15 20:05:43 +00:00
if not tonumber(dx) then error('moveTowardsX: Invalid arguments') end
2018-01-24 22:39:38 +00:00
local direction = dx - turtle.point.x
local move
2017-10-08 21:45:01 +00:00
2018-01-24 22:39:38 +00:00
if direction == 0 then
return true
end
2017-10-08 21:45:01 +00:00
2018-01-24 22:39:38 +00:00
if direction > 0 and turtle.point.heading == 0 or
direction < 0 and turtle.point.heading == 2 then
move = turtle.forward
else
move = turtle.back
end
2016-12-11 19:24:52 +00:00
2018-01-24 22:39:38 +00:00
repeat
if not move() then
return false
end
until turtle.point.x == dx
return true
2016-12-11 19:24:52 +00:00
end
2017-11-15 05:08:42 +00:00
local function moveTowardsZ(dz)
2018-01-24 22:39:38 +00:00
local direction = dz - turtle.point.z
local move
2016-12-11 19:24:52 +00:00
2018-01-24 22:39:38 +00:00
if direction == 0 then
return true
end
2017-10-08 21:45:01 +00:00
2018-01-24 22:39:38 +00:00
if direction > 0 and turtle.point.heading == 1 or
direction < 0 and turtle.point.heading == 3 then
move = turtle.forward
else
move = turtle.back
end
2016-12-11 19:24:52 +00:00
2018-01-24 22:39:38 +00:00
repeat
if not move() then
return false
end
until turtle.point.z == dz
return true
2016-12-11 19:24:52 +00:00
end
-- [[ go ]] --
-- 1 turn goto (going backwards if possible)
2017-11-15 05:08:42 +00:00
function turtle.gotoSingleTurn(dx, dy, dz, dh)
2018-01-24 22:39:38 +00:00
dx = dx or turtle.point.x
dy = dy or turtle.point.y
dz = dz or turtle.point.z
local function gx()
if turtle.point.x ~= dx then
moveTowardsX(dx)
end
if turtle.point.z ~= dz then
if dh and dh % 2 == 1 then
turtle.setHeading(dh)
else
turtle.headTowardsZ(dz)
end
end
end
local function gz()
if turtle.point.z ~= dz then
moveTowardsZ(dz)
end
if turtle.point.x ~= dx then
if dh and dh % 2 == 0 then
turtle.setHeading(dh)
else
turtle.headTowardsX(dx)
end
end
end
repeat
local x, z
local y = turtle.point.y
repeat
x, z = turtle.point.x, turtle.point.z
if turtle.point.heading % 2 == 0 then
gx()
gz()
else
gz()
gx()
end
until x == turtle.point.x and z == turtle.point.z
if turtle.point.y ~= dy then
turtle.gotoY(dy)
end
if turtle.point.x == dx and turtle.point.z == dz and turtle.point.y == dy then
return true
end
until x == turtle.point.x and z == turtle.point.z and y == turtle.point.y
return false
2016-12-11 19:24:52 +00:00
end
2017-11-15 05:08:42 +00:00
local function gotoEx(dx, dy, dz)
2018-01-24 22:39:38 +00:00
-- determine the heading to ensure the least amount of turns
-- first check is 1 turn needed - remaining require 2 turns
if turtle.point.heading == 0 and turtle.point.x <= dx or
turtle.point.heading == 2 and turtle.point.x >= dx or
turtle.point.heading == 1 and turtle.point.z <= dz or
turtle.point.heading == 3 and turtle.point.z >= dz then
-- maintain current heading
-- nop
elseif dz > turtle.point.z and turtle.point.heading == 0 or
dz < turtle.point.z and turtle.point.heading == 2 or
dx < turtle.point.x and turtle.point.heading == 1 or
dx > turtle.point.x and turtle.point.heading == 3 then
turtle.turnRight()
else
turtle.turnLeft()
end
if (turtle.point.heading % 2) == 1 then
if not turtle.gotoZ(dz) then return false end
if not turtle.gotoX(dx) then return false end
else
if not turtle.gotoX(dx) then return false end
if not turtle.gotoZ(dz) then return false end
end
if dy then
if not turtle.gotoY(dy) then return false end
end
return true
2016-12-11 19:24:52 +00:00
end
-- fallback goto - will turn around if was previously moving backwards
2017-11-15 05:08:42 +00:00
local function gotoMultiTurn(dx, dy, dz)
2018-01-24 22:39:38 +00:00
if gotoEx(dx, dy, dz) then
return true
end
2016-12-11 19:24:52 +00:00
2018-01-24 22:39:38 +00:00
local moved
repeat
local x, y, z = turtle.point.x, turtle.point.y, turtle.point.z
2016-12-11 19:24:52 +00:00
2018-01-24 22:39:38 +00:00
-- try going the other way
if (turtle.point.heading % 2) == 1 then
turtle.headTowardsX(dx)
else
turtle.headTowardsZ(dz)
end
2016-12-11 19:24:52 +00:00
2018-04-02 03:25:33 +00:00
if gotoEx(dx, dy, dz) then
2018-01-24 22:39:38 +00:00
return true
end
2016-12-11 19:24:52 +00:00
2018-01-24 22:39:38 +00:00
if dy then
turtle.gotoY(dy)
end
2016-12-11 19:24:52 +00:00
2018-01-24 22:39:38 +00:00
moved = x ~= turtle.point.x or y ~= turtle.point.y or z ~= turtle.point.z
until not moved
2016-12-11 19:24:52 +00:00
2018-01-24 22:39:38 +00:00
return false
2016-12-11 19:24:52 +00:00
end
-- go backwards - turning around if necessary to fight mobs / break blocks
function turtle.goback()
2018-01-24 22:39:38 +00:00
local hi = headings[turtle.point.heading]
return turtle.go({
2018-01-24 22:39:38 +00:00
x = turtle.point.x - hi.xd,
y = turtle.point.y,
z = turtle.point.z - hi.zd,
heading = turtle.point.heading,
})
2016-12-11 19:24:52 +00:00
end
function turtle.gotoYfirst(pt)
if turtle.gotoY(pt.y) then
if turtle.go(pt) then
2018-01-24 22:39:38 +00:00
turtle.setHeading(pt.heading)
return true
end
end
2016-12-11 19:24:52 +00:00
end
function turtle.go(pt)
if not pt.x and not pt.z and pt.y then
if turtle.gotoY(pt.y) then
turtle.setHeading(pt.heading)
return true
end
return false, 'Failed to reach location'
end
local dx = pt.x or turtle.point.x
local dz = pt.z or turtle.point.z
local dy, dh = pt.y, pt.heading
2018-01-24 22:39:38 +00:00
if not turtle.gotoSingleTurn(dx, dy, dz, dh) then
if not gotoMultiTurn(dx, dy, dz) then
2018-10-14 19:35:40 +00:00
return false, 'Failed to reach location'
2018-01-24 22:39:38 +00:00
end
end
turtle.setHeading(dh)
2018-10-14 19:35:40 +00:00
return pt
2016-12-11 19:24:52 +00:00
end
2017-10-12 21:58:35 +00:00
-- avoid lint errors
-- deprecated
turtle['goto'] = turtle.go
turtle['_goto'] = turtle.go
2017-10-12 21:58:35 +00:00
2019-03-09 01:50:50 +00:00
-- TODO: localize these goto functions
2016-12-11 19:24:52 +00:00
function turtle.gotoX(dx)
2018-01-24 22:39:38 +00:00
turtle.headTowardsX(dx)
2016-12-11 19:24:52 +00:00
2018-01-24 22:39:38 +00:00
while turtle.point.x ~= dx do
if not turtle.forward() then
return false
end
end
return true
2016-12-11 19:24:52 +00:00
end
function turtle.gotoZ(dz)
2018-01-24 22:39:38 +00:00
turtle.headTowardsZ(dz)
2016-12-11 19:24:52 +00:00
2018-01-24 22:39:38 +00:00
while turtle.point.z ~= dz do
if not turtle.forward() then
return false
end
end
return true
2016-12-11 19:24:52 +00:00
end
function turtle.gotoY(dy)
2018-01-24 22:39:38 +00:00
while turtle.point.y > dy do
if not turtle.down() then
return false
end
end
2017-10-08 21:45:01 +00:00
2018-01-24 22:39:38 +00:00
while turtle.point.y < dy do
if not turtle.up() then
return false
end
end
return true
2016-12-11 19:24:52 +00:00
end
2019-01-17 18:31:05 +00:00
-- [[ Inventory ]] --
2016-12-11 19:24:52 +00:00
function turtle.getSlot(indexOrId, slots)
2018-01-24 22:39:38 +00:00
if type(indexOrId) == 'string' then
slots = slots or turtle.getInventory()
local _,c = string.gsub(indexOrId, ':', '')
if c == 2 then -- combined id and dmg .. ie. minecraft:coal:0
2019-01-18 04:33:19 +00:00
return Util.find(slots, 'key', indexOrId)
2018-01-24 22:39:38 +00:00
end
2019-01-18 04:33:19 +00:00
return Util.find(slots, 'name', indexOrId)
2018-01-24 22:39:38 +00:00
end
local detail = turtle.getItemDetail(indexOrId)
if detail then
return {
name = detail.name,
damage = detail.damage,
count = detail.count,
key = detail.name .. ':' .. detail.damage,
index = indexOrId,
-- deprecate
qty = detail.count,
dmg = detail.damage,
id = detail.name,
}
end
2018-10-14 19:35:40 +00:00
-- inconsistent return value
-- null is returned if indexOrId is a string and no item is present
2018-01-24 22:39:38 +00:00
return {
qty = 0, -- deprecate
count = 0,
index = indexOrId,
}
2016-12-11 19:24:52 +00:00
end
function turtle.select(indexOrId)
2018-01-24 22:39:38 +00:00
if type(indexOrId) == 'number' then
return turtle.native.select(indexOrId)
end
2016-12-11 19:24:52 +00:00
2018-01-24 22:39:38 +00:00
local s = turtle.getSlot(indexOrId)
if s then
turtle.native.select(s.index)
return s
end
2016-12-11 19:24:52 +00:00
2018-01-24 22:39:38 +00:00
return false, 'Inventory does not contain item'
2016-12-11 19:24:52 +00:00
end
function turtle.getInventory(slots)
2018-01-24 22:39:38 +00:00
slots = slots or { }
for i = 1, 16 do
slots[i] = turtle.getSlot(i)
end
return slots
2016-12-11 19:24:52 +00:00
end
function turtle.getSummedInventory()
2018-01-24 22:39:38 +00:00
local slots = turtle.getFilledSlots()
local t = { }
for _,slot in pairs(slots) do
2019-01-18 04:33:19 +00:00
local entry = t[slot.key]
2018-01-24 22:39:38 +00:00
if not entry then
entry = {
count = 0,
damage = slot.damage,
name = slot.name,
key = slot.key,
-- deprecate
qty = 0,
dmg = slot.dmg,
id = slot.id,
}
2019-01-18 04:33:19 +00:00
t[slot.key] = entry
2018-01-24 22:39:38 +00:00
end
entry.qty = entry.qty + slot.qty
entry.count = entry.qty
end
return t
end
2017-12-11 16:31:41 +00:00
function turtle.has(item, count)
2018-10-14 19:35:40 +00:00
if item:match('.*:%d') then
local slot = turtle.getSummedInventory()[item]
return slot and slot.count >= (count or 1)
end
local slot = turtle.getSlot(item)
2019-01-05 15:35:25 +00:00
return slot and slot.count >= (count or 1)
2017-12-11 16:31:41 +00:00
end
2016-12-11 19:24:52 +00:00
function turtle.getFilledSlots(startSlot)
2018-01-24 22:39:38 +00:00
startSlot = startSlot or 1
2016-12-11 19:24:52 +00:00
2018-01-24 22:39:38 +00:00
local slots = { }
for i = startSlot, 16 do
local count = turtle.getItemCount(i)
if count > 0 then
slots[i] = turtle.getSlot(i)
end
end
return slots
2016-12-11 19:24:52 +00:00
end
function turtle.eachFilledSlot(fn)
2018-01-24 22:39:38 +00:00
local slots = turtle.getFilledSlots()
for _,slot in pairs(slots) do
fn(slot)
end
2016-12-11 19:24:52 +00:00
end
2017-09-15 05:08:04 +00:00
function turtle.emptyInventory(dropAction)
2018-01-24 22:39:38 +00:00
dropAction = dropAction or turtle.native.drop
turtle.eachFilledSlot(function(slot)
turtle.select(slot.index)
dropAction()
end)
turtle.select(1)
2017-09-15 05:08:04 +00:00
end
2016-12-11 19:24:52 +00:00
function turtle.reconcileInventory(slots, dropAction)
2018-01-24 22:39:38 +00:00
dropAction = dropAction or turtle.native.drop
for _,s in pairs(slots) do
local qty = turtle.getItemCount(s.index)
if qty > s.qty then
turtle.select(s.index)
dropAction(qty-s.qty, s)
end
end
2016-12-11 19:24:52 +00:00
end
function turtle.selectSlotWithItems(startSlot)
2018-01-24 22:39:38 +00:00
startSlot = startSlot or 1
for i = startSlot, 16 do
if turtle.getItemCount(i) > 0 then
turtle.select(i)
return i
end
end
2016-12-11 19:24:52 +00:00
end
function turtle.selectSlotWithQuantity(qty, startSlot)
2018-01-24 22:39:38 +00:00
startSlot = startSlot or 1
2016-12-11 19:24:52 +00:00
2018-01-24 22:39:38 +00:00
for i = startSlot, 16 do
if turtle.getItemCount(i) == qty then
turtle.select(i)
return i
end
end
2016-12-11 19:24:52 +00:00
end
2017-09-15 05:08:04 +00:00
function turtle.selectOpenSlot(startSlot)
2018-01-24 22:39:38 +00:00
return turtle.selectSlotWithQuantity(0, startSlot)
2017-09-15 05:08:04 +00:00
end
function turtle.condense()
2018-01-24 22:39:38 +00:00
local slots = turtle.getInventory()
2018-12-16 07:28:16 +00:00
for i = 1, 16 do
if slots[i].count < 64 then
for j = 16, i + 1, -1 do
if slots[j].count > 0 and (slots[i].count == 0 or slots[i].key == slots[j].key) then
turtle.select(j)
if turtle.transferTo(i) then
2018-12-27 08:05:12 +00:00
local transferred = turtle.getItemCount(i) - slots[i].count
2018-12-16 07:28:16 +00:00
slots[j].count = slots[j].count - transferred
slots[i].count = slots[i].count + transferred
slots[i].key = slots[j].key
2018-12-16 07:44:01 +00:00
if slots[j].count == 0 then
slots[j].key = nil
end
2018-12-16 07:28:16 +00:00
if slots[i].count == 64 then
break
end
else
2018-01-24 22:39:38 +00:00
break
end
end
end
end
end
2018-12-16 07:28:16 +00:00
turtle.select(1)
2018-01-24 22:39:38 +00:00
return true
end
function turtle.getItemCount(idOrName)
2018-01-24 22:39:38 +00:00
if type(idOrName) == 'number' then
return turtle.native.getItemCount(idOrName)
end
local slots = turtle.getFilledSlots()
local count = 0
for _,slot in pairs(slots) do
2019-01-18 04:33:19 +00:00
if slot.key == idOrName or slot.name == idOrName then
count = count + slot.count
2018-01-24 22:39:38 +00:00
end
end
return count
end
2019-01-17 18:31:05 +00:00
-- [[ Equipment ]] --
function turtle.equip(side, item)
2018-01-24 22:39:38 +00:00
if item then
if not turtle.select(item) then
return false, 'Unable to equip ' .. item
end
end
2018-01-24 22:39:38 +00:00
if side == 'left' then
return turtle.equipLeft()
end
return turtle.equipRight()
end
2017-10-31 06:01:18 +00:00
function turtle.isEquipped(item)
2018-01-24 22:39:38 +00:00
if peripheral.getType('left') == item then
return 'left'
elseif peripheral.getType('right') == item then
return 'right'
end
2017-10-31 06:01:18 +00:00
end
function turtle.unequip(side)
if not turtle.selectSlotWithQuantity(0) then
return false, 'No slots available'
end
return turtle.equip(side)
end
2019-01-18 04:33:19 +00:00
-- deprecate
function turtle.run(fn, ...)
2018-01-24 22:39:38 +00:00
local args = { ... }
local s, m
2018-01-24 22:39:38 +00:00
if type(fn) == 'string' then
fn = turtle[fn]
end
2018-01-24 22:39:38 +00:00
synchronized(turtle, function()
turtle.resetState()
s, m = pcall(function() fn(table.unpack(args)) end)
2018-01-24 22:39:38 +00:00
turtle.resetState()
if not s and m then
_G.printError(m)
end
end)
2018-01-24 22:39:38 +00:00
return s, m
end
2017-10-28 00:24:48 +00:00
function turtle.abort(abort)
2018-01-24 22:39:38 +00:00
state.abort = abort
if abort then
os.queueEvent('turtle_abort')
end
end
-- [[ Pathing ]] --
2017-10-26 22:56:55 +00:00
function turtle.setPersistent(isPersistent)
2018-01-24 22:39:38 +00:00
if isPersistent then
Pathing.setBlocks({ })
else
Pathing.setBlocks()
end
2017-10-26 22:56:55 +00:00
end
function turtle.setPathingBox(box)
2018-01-24 22:39:38 +00:00
Pathing.setBox(box)
2017-10-26 22:56:55 +00:00
end
function turtle.addWorldBlock(pt)
2018-01-24 22:39:38 +00:00
Pathing.addBlock(pt)
2017-10-26 22:56:55 +00:00
end
function turtle.addWorldBlocks(pts)
Util.each(pts, function(pt)
Pathing.addBlock(pt)
end)
end
2018-10-14 19:35:40 +00:00
local movementStrategy = turtle.pathfind
function turtle.setMovementStrategy(strategy)
if strategy == 'pathing' then
movementStrategy = turtle.pathfind
elseif strategy == 'goto' then
movementStrategy = turtle.go
2018-10-14 19:35:40 +00:00
else
error('Invalid movement strategy')
end
end
2017-10-26 22:56:55 +00:00
function turtle.faceAgainst(pt, options) -- 4 sided
2018-01-24 22:39:38 +00:00
options = options or { }
options.dest = { }
2018-01-24 22:39:38 +00:00
for i = 0, 3 do
local hi = Point.facings[i]
table.insert(options.dest, {
x = pt.x + hi.xd,
z = pt.z + hi.zd,
y = pt.y + hi.yd,
heading = (hi.heading + 2) % 4,
})
end
2018-10-14 19:35:40 +00:00
return movementStrategy(Point.closest(turtle.point, options.dest), options)
end
2017-10-31 06:01:18 +00:00
-- move against this point
-- if the point does not contain a heading, then the turtle
-- will face the block (if on same plane)
-- if above or below, the heading is undetermined unless specified
2017-09-15 05:08:04 +00:00
function turtle.moveAgainst(pt, options) -- 6 sided
2018-01-24 22:39:38 +00:00
options = options or { }
options.dest = { }
for i = 0, 5 do
local hi = turtle.getHeadingInfo(i)
local heading, direction
if i < 4 then
heading = (hi.heading + 2) % 4
direction = 'forward'
elseif i == 4 then
direction = 'down'
elseif i == 5 then
direction = 'up'
end
table.insert(options.dest, {
x = pt.x + hi.xd,
z = pt.z + hi.zd,
y = pt.y + hi.yd,
direction = direction,
heading = pt.heading or heading,
})
end
2018-10-14 19:35:40 +00:00
return movementStrategy(Point.closest(turtle.point, options.dest), options)
end
local actionsAt = {
2018-01-24 22:39:38 +00:00
detect = {
up = turtle.detectUp,
down = turtle.detectDown,
forward = turtle.detect,
},
dig = {
up = turtle.digUp,
down = turtle.digDown,
forward = turtle.dig,
},
move = {
up = turtle.moveUp,
down = turtle.moveDown,
forward = turtle.move,
},
attack = {
up = turtle.attackUp,
down = turtle.attackDown,
forward = turtle.attack,
},
place = {
up = turtle.placeUp,
down = turtle.placeDown,
forward = turtle.place,
},
drop = {
up = turtle.dropUp,
down = turtle.dropDown,
forward = turtle.drop,
},
suck = {
up = turtle.suckUp,
down = turtle.suckDown,
forward = turtle.suck,
},
compare = {
up = turtle.compareUp,
down = turtle.compareDown,
forward = turtle.compare,
},
inspect = {
up = turtle.inspectUp,
down = turtle.inspectDown,
forward = turtle.inspect,
},
}
2017-10-31 06:01:18 +00:00
-- pt = { x,y,z,heading,direction }
-- direction should only be up or down if provided
-- heading can be provided to tell which way to face during action
-- ex: place a block at the point from above facing east
local function _actionAt(action, pt, ...)
2018-01-24 22:39:38 +00:00
if not pt.heading and not pt.direction then
local msg
pt, msg = turtle.moveAgainst(pt)
if pt then
return action[pt.direction](...)
end
return pt, msg
end
local reversed =
{ [0] = 2, [1] = 3, [2] = 0, [3] = 1, [4] = 5, [5] = 4, }
local dir = reversed[headings[pt.direction or pt.heading].heading]
local apt = { x = pt.x + headings[dir].xd,
y = pt.y + headings[dir].yd,
z = pt.z + headings[dir].zd, }
local direction
-- ex: place a block at this point, from above, facing east
if dir < 4 then
apt.heading = (dir + 2) % 4
direction = 'forward'
elseif dir == 4 then
apt.heading = pt.heading
direction = 'down'
elseif dir == 5 then
apt.heading = pt.heading
direction = 'up'
end
2018-10-14 19:35:40 +00:00
if movementStrategy(apt) then
2018-01-24 22:39:38 +00:00
return action[direction](...)
end
2017-10-31 06:01:18 +00:00
end
local function _actionDownAt(action, pt, ...)
2018-01-24 22:39:38 +00:00
pt = Util.shallowCopy(pt)
pt.direction = Point.DOWN
return _actionAt(action, pt, ...)
2017-10-31 06:01:18 +00:00
end
local function _actionUpAt(action, pt, ...)
2018-01-24 22:39:38 +00:00
pt = Util.shallowCopy(pt)
pt.direction = Point.UP
return _actionAt(action, pt, ...)
2017-10-31 06:01:18 +00:00
end
local function _actionForwardAt(action, pt, ...)
2018-01-24 22:39:38 +00:00
if turtle.faceAgainst(pt) then
return action.forward(...)
end
2017-10-28 00:24:48 +00:00
end
function turtle.detectAt(pt) return _actionAt(actionsAt.detect, pt) end
function turtle.detectDownAt(pt) return _actionDownAt(actionsAt.detect, pt) end
function turtle.detectForwardAt(pt) return _actionForwardAt(actionsAt.detect, pt) end
function turtle.detectUpAt(pt) return _actionUpAt(actionsAt.detect, pt) end
2019-01-13 18:24:37 +00:00
function turtle.digAt(pt, ...) return _actionAt(actionsAt.dig, pt, ...) end
function turtle.digDownAt(pt, ...) return _actionDownAt(actionsAt.dig, pt, ...) end
function turtle.digForwardAt(pt, ...) return _actionForwardAt(actionsAt.dig, pt, ...) end
function turtle.digUpAt(pt, ...) return _actionUpAt(actionsAt.dig, pt, ...) end
2017-10-28 00:24:48 +00:00
function turtle.attackAt(pt) return _actionAt(actionsAt.attack, pt) end
function turtle.attackDownAt(pt) return _actionDownAt(actionsAt.attack, pt) end
function turtle.attackForwardAt(pt) return _actionForwardAt(actionsAt.attack, pt) end
function turtle.attackUpAt(pt) return _actionUpAt(actionsAt.attack, pt) end
2017-10-31 06:01:18 +00:00
function turtle.placeAt(pt, arg, dir) return _actionAt(actionsAt.place, pt, arg, dir) end
2017-10-28 00:24:48 +00:00
function turtle.placeDownAt(pt, arg) return _actionDownAt(actionsAt.place, pt, arg) end
function turtle.placeForwardAt(pt, arg) return _actionForwardAt(actionsAt.place, pt, arg) end
function turtle.placeUpAt(pt, arg) return _actionUpAt(actionsAt.place, pt, arg) end
function turtle.dropAt(pt, ...) return _actionAt(actionsAt.drop, pt, ...) end
function turtle.dropDownAt(pt, ...) return _actionDownAt(actionsAt.drop, pt, ...) end
function turtle.dropForwardAt(pt, ...) return _actionForwardAt(actionsAt.drop, pt, ...) end
function turtle.dropUpAt(pt, ...) return _actionUpAt(actionsAt.drop, pt, ...) end
function turtle.suckAt(pt, qty) return _actionAt(actionsAt.suck, pt, qty or 64) end
function turtle.suckDownAt(pt, qty) return _actionDownAt(actionsAt.suck, pt, qty or 64) end
function turtle.suckForwardAt(pt, qty) return _actionForwardAt(actionsAt.suck, pt, qty or 64) end
function turtle.suckUpAt(pt, qty) return _actionUpAt(actionsAt.suck, pt, qty or 64) end
function turtle.compareAt(pt) return _actionAt(actionsAt.compare, pt) end
function turtle.compareDownAt(pt) return _actionDownAt(actionsAt.compare, pt) end
function turtle.compareForwardAt(pt) return _actionForwardAt(actionsAt.compare, pt) end
function turtle.compareUpAt(pt) return _actionUpAt(actionsAt.compare, pt) end
function turtle.inspectAt(pt) return _actionAt(actionsAt.inspect, pt) end
function turtle.inspectDownAt(pt) return _actionDownAt(actionsAt.inspect, pt) end
function turtle.inspectForwardAt(pt) return _actionForwardAt(actionsAt.inspect, pt) end
function turtle.inspectUpAt(pt) return _actionUpAt(actionsAt.inspect, pt) end
2019-01-17 18:31:05 +00:00
turtle.reset()