211 lines
6.6 KiB
Lua
211 lines
6.6 KiB
Lua
--[[
|
|
Movescript - A simplified robot script for ComputerCraft.
|
|
|
|
Author: Andrew Lalis <andrewlalisofficial@gmail.com>
|
|
|
|
Movescript provides a simpler, conciser way to program "turtles" (robots), so
|
|
that you don't need to get tired of typing "turtle.forward()" over and over.
|
|
|
|
]]--
|
|
VERSION = "0.0.1"
|
|
|
|
local t = turtle
|
|
|
|
-- The movescript module. Functions defined within this table are exported.
|
|
local movescript = {}
|
|
|
|
movescript.defaultSettings = {
|
|
debug = false,
|
|
safe = true,
|
|
destructive = false,
|
|
fuels = {"minecraft:coal", "minecraft:charcoal"}
|
|
}
|
|
|
|
local function debug(msg, settings)
|
|
if settings and settings.debug then
|
|
print("[MS] " .. msg)
|
|
end
|
|
end
|
|
|
|
-- Helper function for turtle to dig backwards.
|
|
function t.digBack(side)
|
|
t.turnRight()
|
|
t.turnRight()
|
|
t.dig(side)
|
|
t.turnRight()
|
|
t.turnRight()
|
|
end
|
|
|
|
-- Helper function for turtle to detect backwards.
|
|
function t.detectBack()
|
|
t.turnRight()
|
|
t.turnRight()
|
|
local result = t.detect()
|
|
t.turnRight()
|
|
t.turnRight()
|
|
return result
|
|
end
|
|
|
|
local function goDirection(dirFunction, digFunction, detectFunction, settings)
|
|
settings = settings or movescript.defaultSettings
|
|
safe = settings.safe or movescript.defaultSettings.safe
|
|
destructive = settings.destructive or movescript.defaultSettings.destructive
|
|
local success = dirFunction()
|
|
if not safe then return end
|
|
while not success do
|
|
debug("Unable to move.", settings)
|
|
if destructive and detectFunction() then
|
|
debug("Detected a block in the way; attempting to remove it.", settings)
|
|
digFunction()
|
|
end
|
|
success = dirFunction()
|
|
end
|
|
end
|
|
|
|
local function goUp(settings)
|
|
debug("Moving up.", settings)
|
|
goDirection(t.up, t.digUp, t.detectUp, settings)
|
|
end
|
|
|
|
local function goDown(settings)
|
|
debug("Moving down.", settings)
|
|
goDirection(t.down, t.digDown, t.detectDown, settings)
|
|
end
|
|
|
|
local function goForward(settings)
|
|
debug("Moving forward.", settings)
|
|
goDirection(t.forward, t.dig, t.detect, settings)
|
|
end
|
|
|
|
local function goBack(settings)
|
|
debug("Moving back.", settings)
|
|
goDirection(t.back, t.digBack, t.detectBack, settings)
|
|
end
|
|
|
|
local function goRight(settings)
|
|
debug("Turning right.", settings)
|
|
t.turnRight()
|
|
end
|
|
|
|
local function goLeft(settings)
|
|
debug("Turning left.", settings)
|
|
t.turnLeft()
|
|
end
|
|
|
|
local actionMap = {
|
|
["U"] = {f = goUp, needsFuel = true},
|
|
["D"] = {f = goDown, needsFuel = true},
|
|
["L"] = {f = goLeft, needsFuel = false},
|
|
["R"] = {f = goRight, needsFuel = false},
|
|
["F"] = {f = goForward, needsFuel = true},
|
|
["B"] = {f = goBack, needsFuel = true},
|
|
["P"] = {f = t.place, needsFuel = false},
|
|
["Pu"] = {f = t.placeUp, needsFuel = false},
|
|
["Pd"] = {f = t.placeDown, needsFuel = false},
|
|
["A"] = {f = t.attack, needsFuel = false},
|
|
["Au"] = {f = t.attackUp, needsFuel = false},
|
|
["Ad"] = {f = t.attackDown, needsFuel = false}
|
|
}
|
|
|
|
-- Tries to refuel the turtle from all slots that contain a valid fuel.
|
|
-- Returns a boolean indicating if at least one piece of fuel was consumed.
|
|
local function refuelAll(settings)
|
|
debug("Refueling...", settings)
|
|
local fuels = settings.fuels or movescript.defaultSettings.fuels
|
|
local refueled = false
|
|
for slot = 1, 16 do
|
|
local item = t.getItemDetail(slot)
|
|
if item ~= nil then
|
|
for _, fuelName in pairs(fuels) do
|
|
if item.name == fuelName then
|
|
t.select(i)
|
|
if t.refuel(item.count) then refueled = true end
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return refueled
|
|
end
|
|
|
|
-- Blocks until the turtle's fuel level is at least at the required level.
|
|
local function refuelToAtLeast(requiredLevel, settings)
|
|
refuelAll(settings)
|
|
while t.getFuelLevel < requiredLevel do
|
|
print(
|
|
"[MS] Fuel level is too low. Level: " .. t.getFuelLevel() .. ". Required: " .. requiredLevel ..
|
|
". Please add some of the following fuels:"
|
|
)
|
|
local fuels = settings.fuels or movescript.defaultSettings.fuels
|
|
for _, fuelName in pairs(fuels) do
|
|
print(" - " .. fuelName)
|
|
end
|
|
local fuelUpdated = false
|
|
while not fuelUpdated do
|
|
os.pullEvent("turtle_inventory")
|
|
fuelUpdated = refuelAll()
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Executes a single instruction. An instruction is a table with an "action"
|
|
-- and some attributes, such as if it needs fuel or not.
|
|
local function executeInstruction(instruction, settings)
|
|
local action = actionMap[instruction.action]
|
|
if action then
|
|
debug("Executing action \"" .. instruction.action .. "\" " .. instruction.count .. " times.", settings)
|
|
local shouldRefuel = (
|
|
(settings.safe or true) and
|
|
(action.needsFuel) and
|
|
(instruction.count > t.getFuelLevel())
|
|
)
|
|
if shouldRefuel then
|
|
local fuelRequired = instruction.count
|
|
refuelToAtLeast(fuelRequired, settings)
|
|
end
|
|
for i = 1, instruction.count do action.f() end
|
|
end
|
|
end
|
|
|
|
-- Parses a movescript script into a series of instruction tables.
|
|
local function parseScript(script, settings)
|
|
local instructions = {}
|
|
for instruction in string.gfind(script, "%W*(%d*%u%l*)%W*") do
|
|
local countIdx, countIdxEnd = string.find(instruction, "%d+")
|
|
local actionIdx, actionIdxEnd = string.find(instruction, "%u%l*")
|
|
local count = 1
|
|
if countIdx ~= nil then
|
|
count = tonumber(string.sub(instruction, countIdx, countIdxEnd))
|
|
end
|
|
local action = string.sub(instruction, actionIdx, actionIdxEnd)
|
|
if count < 1 or count > t.getFuelLimit() then
|
|
error("Instruction at index " .. actionIdx .. " has an invalid count of " .. count .. ". It should be >= 1 and <= " .. t.getFuelLimit())
|
|
end
|
|
if actionMap[action] == nil then
|
|
error("Instruction at index " .. actionIdx .. ", \"" .. action .. "\", does not refer to a valid action.")
|
|
end
|
|
table.insert(instructions, {action = action, count = count})
|
|
debug("Parsed instruction: " .. instruction, settings)
|
|
end
|
|
return instructions
|
|
end
|
|
|
|
function movescript.run(script, settings)
|
|
settings = settings or movescript.defaultSettings
|
|
script = script or ""
|
|
debug("Executing script: " .. script, settings)
|
|
local instructions = parseScript(script, settings)
|
|
for idx, instruction in pairs(instructions) do
|
|
executeInstruction(instruction, settings)
|
|
end
|
|
end
|
|
|
|
function movescript.runFile(filename, settings)
|
|
local f = fs.open(filename, "r")
|
|
local script = f.readAll()
|
|
f.close()
|
|
movescript.run(script, settings)
|
|
end
|
|
|
|
return movescript
|