2021-08-28 23:12:29 -05:00

320 lines
8.0 KiB
Lua

-- CC0/Unlicense system32 2020
turtle = {}
local mod_prefix = minetest.get_modpath(minetest.get_current_modname())
tlang = dofile(mod_prefix .. "/tlang.lua")
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
})
turtle.states = {}
turtle.states_available = false
function turtle.schedule(name, state)
turtle.states[#turtle.states + 1] = {name = name, state = state}
turtle.states_available = true
end
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
end
end
for i, v in ipairs(dead) do
table.remove(turtle.states, v)
end
turtle.states_available = #turtle.states ~= 0
end
end
minetest.register_globalstep(turtle.run_states)
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
})