2020-10-14 13:00:32 +00:00
|
|
|
-- CC0/Unlicense system32 2020
|
|
|
|
|
|
|
|
turtle = {}
|
|
|
|
|
2020-11-05 19:11:17 +00:00
|
|
|
local mod_prefix = minetest.get_modpath(minetest.get_current_modname())
|
|
|
|
tlang = dofile(mod_prefix .. "/tlang.lua")
|
|
|
|
|
2020-10-14 13:00:32 +00:00
|
|
|
function turtle.coord(x, y, z)
|
|
|
|
return {x = x, y = y, z = z}
|
|
|
|
end
|
|
|
|
|
|
|
|
turtle.pos1 = turtle.coord(0, 0, 0)
|
|
|
|
turtle.pos2 = turtle.coord(0, 0, 0)
|
|
|
|
|
|
|
|
local function format_coord(c)
|
|
|
|
return tostring(c.x) .. " " .. tostring(c.y) .. " " .. tostring(c.z)
|
|
|
|
end
|
|
|
|
|
|
|
|
local function parse_coord(c)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- can include ~ + - along with num and ,
|
|
|
|
local function parse_relative_coord(c)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- x or {x,y,z}
|
|
|
|
function turtle.optcoord(x, y, z)
|
|
|
|
local pos = x
|
|
|
|
if y and z then
|
|
|
|
pos = turtle.coord(x, y, z)
|
|
|
|
end
|
|
|
|
return pos
|
|
|
|
end
|
|
|
|
|
|
|
|
-- swap x and y if x > y
|
|
|
|
local function swapg(x, y)
|
|
|
|
if x > y then
|
|
|
|
return y, x
|
|
|
|
else
|
|
|
|
return x, y
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- swaps coordinates around such that (matching ords of) c1 < c2 and the overall cuboid is the same shape
|
|
|
|
function turtle.rectify(c1, c2)
|
|
|
|
c1.x, c2.x = swapg(c1.x, c2.x)
|
|
|
|
c1.y, c2.y = swapg(c1.y, c2.y)
|
|
|
|
c1.z, c2.z = swapg(c1.z, c2.z)
|
|
|
|
return c1, c2
|
|
|
|
end
|
|
|
|
|
|
|
|
-- converts a coordinate to a system where 0,0 is the southwestern corner of the world
|
|
|
|
function turtle.zeroidx(c)
|
|
|
|
local side = 30912
|
|
|
|
return turtle.coord(c.x + side, c.y + side, c.z + side)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- swaps coords and subtracts such that c1 == {0, 0, 0} and c2 is the distance from c1
|
|
|
|
-- returns rectified c1/c2 and the relativized version
|
|
|
|
function turtle.relativize(c1, c2)
|
|
|
|
c1, c2 = turtle.rectify(c1, c2)
|
|
|
|
|
|
|
|
local c1z = turtle.zeroidx(c1)
|
|
|
|
local c2z = turtle.zeroidx(c2)
|
|
|
|
|
|
|
|
local rel = turtle.coord(c2z.x - c1z.x, c2z.y - c1z.y, c2z.z - c1z.z)
|
|
|
|
|
|
|
|
return c1, rel
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- get the inventory index of the best tool to mine x, y, z
|
|
|
|
-- returns a wield index, which starts at 0
|
|
|
|
function turtle.get_best_tool_index(x, y, z)
|
|
|
|
local node = minetest.get_node_or_nil(turtle.optcoord(x, y, z))
|
|
|
|
if not node then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local nodecaps = minetest.get_node_def(node.name).groups
|
|
|
|
|
|
|
|
local idx = minetest.localplayer:get_wield_index() + 1
|
|
|
|
local best = math.huge
|
|
|
|
|
|
|
|
for i, v in ipairs(minetest.get_inventory("current_player").main) do
|
|
|
|
for gk, gv in pairs(v:get_tool_capabilities().groupcaps) do
|
|
|
|
local level = nodecaps[gk]
|
|
|
|
if level and gv.times[level] < best then
|
|
|
|
idx = i
|
|
|
|
best = gv.times[level]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return idx - 1
|
|
|
|
end
|
|
|
|
|
|
|
|
-- switch to the fastest tool to mine x, y, z
|
|
|
|
function turtle.switch_best(x, y, z)
|
|
|
|
local prev = minetest.localplayer:get_wield_index()
|
|
|
|
|
|
|
|
local index = turtle.get_best_tool_index(x, y, z)
|
|
|
|
|
|
|
|
if prev ~= index then
|
|
|
|
minetest.localplayer:set_wield_index(index)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function turtle.mine(x, y, z)
|
|
|
|
turtle.switch_best(x, y, z)
|
|
|
|
minetest.dig_node(turtle.optcoord(x, y, z))
|
|
|
|
end
|
|
|
|
|
|
|
|
function turtle.place(x, y, z)
|
|
|
|
minetest.place_node(turtle.optcoord(x, y, z))
|
|
|
|
end
|
|
|
|
|
|
|
|
function turtle.cadd(c1, c2)
|
|
|
|
return turtle.coord(c1.x + c2.x, c1.y + c2.y, c1.z + c2.z)
|
|
|
|
end
|
|
|
|
|
|
|
|
function turtle.relcoord(x, y, z)
|
|
|
|
local pos = minetest.localplayer:get_pos()
|
|
|
|
return turtle.cadd(pos, turtle.optcoord(x, y, z))
|
|
|
|
end
|
|
|
|
|
|
|
|
local function between(x, y, z) -- x is between y and z (inclusive)
|
|
|
|
return y <= x and x <= z
|
|
|
|
end
|
|
|
|
|
|
|
|
function turtle.dircoord(f, y, r)
|
|
|
|
local rot = minetest.localplayer:get_yaw() % 360
|
|
|
|
|
|
|
|
if between(rot, 315, 360) or between(rot, 0, 45) then -- north
|
|
|
|
return turtle.relcoord(r, y, f)
|
|
|
|
elseif between(rot, 135, 225) then -- south
|
|
|
|
return turtle.relcoord(-r, y, -f)
|
|
|
|
elseif between(rot, 225, 315) then -- east
|
|
|
|
return turtle.relcoord(f, y, r)
|
|
|
|
elseif between(rot, 45, 135) then -- west
|
|
|
|
return turtle.relcoord(-f, y, -r)
|
|
|
|
end
|
|
|
|
return turtle.relcoord(0, 0, 0)
|
|
|
|
end
|
|
|
|
|
|
|
|
function turtle.move(x, y, z)
|
|
|
|
minetest.localplayer:set_pos(turtle.optcoord(x, y, z))
|
|
|
|
end
|
|
|
|
|
|
|
|
function turtle.advance(amount)
|
|
|
|
amount = amount or 1
|
|
|
|
turtle.move(turtle.dircoord(amount, 0, 0))
|
|
|
|
end
|
|
|
|
|
|
|
|
function turtle.descend(amount)
|
|
|
|
amount = amount or 1
|
|
|
|
turtle.move(turtle.relcoord(0, -amount, 0))
|
|
|
|
end
|
|
|
|
|
|
|
|
function turtle.rotate_abs(deg)
|
|
|
|
minetest.localplayer:set_yaw(deg)
|
|
|
|
end
|
|
|
|
|
|
|
|
function turtle.rotate(deg)
|
|
|
|
local prev = minetest.localplayer:get_yaw()
|
|
|
|
minetest.localplayer:set_yaw((prev + deg) % 360)
|
|
|
|
end
|
|
|
|
|
|
|
|
function turtle.rotate_right(deg)
|
|
|
|
deg = deg or 90
|
|
|
|
turtle.rotate(-deg)
|
|
|
|
end
|
|
|
|
|
|
|
|
function turtle.rotate_left(deg)
|
|
|
|
deg = deg or 90
|
|
|
|
turtle.rotate(deg)
|
|
|
|
end
|
|
|
|
|
|
|
|
function turtle.isblock(block, x, y, z)
|
|
|
|
local node = minetest.get_node_or_nil(turtle.optcoord(x, y, z))
|
|
|
|
return node ~= nil and block == node.name
|
|
|
|
end
|
|
|
|
|
|
|
|
function turtle.checkmine(x, y, z)
|
|
|
|
while true do
|
|
|
|
turtle.mine(x, y, z)
|
|
|
|
busysleep(0.125)
|
|
|
|
-- i hate lua
|
|
|
|
minetest.log(tostring(turtle.isblock("air", x, y, z)))
|
|
|
|
if turtle.isblock("air", x, y, z) then
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function turtle.tp(coords)
|
|
|
|
minetest.localplayer:set_pos(coords)
|
|
|
|
end
|
|
|
|
|
|
|
|
function turtle.moveto(x, y, z)
|
|
|
|
turtle.tp(turtle.optcoord(x, y, z))
|
|
|
|
end
|
|
|
|
|
|
|
|
function turtle.linemine(distance, func)
|
|
|
|
for i = 1, distance do
|
|
|
|
turtle.checkmine(turtle.dircoord(1, 1, 0))
|
|
|
|
turtle.checkmine(turtle.dircoord(1, 0, 0))
|
|
|
|
turtle.advance()
|
|
|
|
|
|
|
|
if func then
|
|
|
|
func()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
local function left_or_right(left)
|
|
|
|
if left then
|
|
|
|
turtle.rotate_left()
|
|
|
|
else
|
|
|
|
turtle.rotate_right()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
local function quarry_clear_liquids()
|
|
|
|
-- puts blocks in front, both sides, and two below where they are liquid
|
|
|
|
-- it does all this one step ahead so no spillage may occur
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- needs to check for liquids (would need to be done in linemine)
|
|
|
|
function turtle.quarry(cstart, cend)
|
|
|
|
-- get a nice cuboid
|
|
|
|
cstart, cend = turtle.rectify(cstart, cend)
|
|
|
|
local start, relend = turtle.relativize(cstart, cend)
|
|
|
|
|
|
|
|
-- makes it start at the top rather than the bottom
|
|
|
|
cend.y, cstart.y = swapg(cend.y, cstart.y)
|
|
|
|
|
|
|
|
-- go to the start
|
|
|
|
turtle.moveto(turtle.cadd(cstart, turtle.coord(0, 1, 0)))
|
|
|
|
turtle.rotate_abs(0)
|
|
|
|
|
|
|
|
-- main loop (zig zag pattern)
|
|
|
|
for height = 0, math.floor(relend.y / 2) do
|
|
|
|
-- go down two blocks
|
|
|
|
turtle.mine(turtle.relcoord(0, -1, 0))
|
|
|
|
turtle.mine(turtle.relcoord(0, -2, 0))
|
|
|
|
turtle.descend(2)
|
|
|
|
|
|
|
|
for width = 0, relend.x do
|
|
|
|
-- swaps left/right rotations each layer and zig zag
|
|
|
|
local leftiness = ((height + width + 1) % 2) == 0
|
|
|
|
|
|
|
|
-- actually mine
|
|
|
|
turtle.linemine(relend.z) -- maybe relend.z to make the end inclusive?
|
|
|
|
left_or_right(leftiness)
|
|
|
|
-- dont rotate at the end of the layer
|
|
|
|
if width ~= relend.x then
|
|
|
|
turtle.linemine(1)
|
|
|
|
left_or_right(leftiness)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- flip around to start again on the next layer
|
|
|
|
turtle.rotate(180)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
minetest.register_chatcommand("quarry", {
|
|
|
|
func = function()
|
|
|
|
turtle.quarry({x = -60, y = 1, z = -60}, {x = -40, y = -5, z = -40})
|
|
|
|
end
|
|
|
|
})
|
|
|
|
|
2020-11-05 19:11:17 +00:00
|
|
|
|
|
|
|
turtle.states = {}
|
2020-11-05 19:53:35 +00:00
|
|
|
turtle.states_available = false
|
2020-11-05 19:11:17 +00:00
|
|
|
|
|
|
|
function turtle.schedule(name, state)
|
2020-11-05 19:53:35 +00:00
|
|
|
turtle.states[#turtle.states + 1] = {name = name, state = state}
|
|
|
|
turtle.states_available = true
|
2020-11-05 19:11:17 +00:00
|
|
|
end
|
|
|
|
|
2020-11-05 19:53:35 +00:00
|
|
|
function turtle.run_states(dtime)
|
|
|
|
if turtle.states_available then
|
|
|
|
local dead = {}
|
|
|
|
|
|
|
|
for i, v in ipairs(turtle.states) do
|
|
|
|
local ret = tlang.step(v.state)
|
|
|
|
if ret ~= true then
|
|
|
|
if type(ret) == "string" then
|
|
|
|
minetest.display_chat_message("Turtle/tlang ERROR in " .. v.name .. ": " .. ret)
|
|
|
|
end
|
|
|
|
dead[#dead + 1] = i
|
2020-11-05 19:11:17 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-11-05 19:53:35 +00:00
|
|
|
for i, v in ipairs(dead) do
|
|
|
|
table.remove(turtle.states, v)
|
|
|
|
end
|
|
|
|
|
|
|
|
turtle.states_available = #turtle.states ~= 0
|
2020-11-05 19:11:17 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
minetest.register_globalstep(turtle.run_states)
|
2020-11-05 23:17:41 +00:00
|
|
|
|
|
|
|
minetest.register_chatcommand("tlang", {
|
|
|
|
description = "Run a tlang program.",
|
|
|
|
params = "<code>",
|
|
|
|
func = function(params)
|
|
|
|
local state = tlang.get_state(params)
|
|
|
|
turtle.schedule("chat_script", state)
|
|
|
|
end
|
|
|
|
})
|