diff --git a/docs/src/guide/movescript/spec.md b/docs/src/guide/movescript/spec.md index 9eb23a6..5f0a6b4 100644 --- a/docs/src/guide/movescript/spec.md +++ b/docs/src/guide/movescript/spec.md @@ -31,20 +31,32 @@ For example: `22(AF)` - We execute the instructions `A` and `F` 22 times. The following table lists all actions that are available in Movescript. Attempting to invoke an action not listed here will result in an error that will terminate your script. -| Action | Description | Needs Fuel | -| ------ | ------------------------------------------------ | ---------- | -| `U` | Move up. | ✅ | -| `D` | Move down. | ✅ | -| `L` | Turn left. | ❌ | -| `R` | Turn right. | ❌ | -| `F` | Move forward. | ✅ | -| `B` | Move backward. | ✅ | -| `P` | Place the selected item in front of the turtle. | ❌ | -| `Pu` | Place the selected item above the turtle. | ❌ | -| `Pd` | Place the selected item below the turtle. | ❌ | -| `A` | Attack in front of the turtle. | ❌ | -| `Au` | Attack above the turtle. | ❌ | -| `Ad` | Attack below the turtle. | ❌ | +| Action | Description | Options | +| ------ | ------------------------------------------------ | ------------------------------------------ | +| `U` | Move up. | +| `D` | Move down. | +| `L` | Turn left. | +| `R` | Turn right. | +| `F` | Move forward. | +| `B` | Move backward. | +| `P` | Place the selected item in front of the turtle. | `text: string` - Text to use if placing a sign. | +| `Pu` | Place the selected item above the turtle. | `text: string` - Text to use if placing a sign. | +| `Pd` | Place the selected item below the turtle. | `text: string` - Text to use if placing a sign. | +| `A` | Attack in front of the turtle. | `side: string` - The tool side to use (left or right). | +| `Au` | Attack above the turtle. | `side: string` - The tool side to use (left or right). | +| `Ad` | Attack below the turtle. | `side: string` - The tool side to use (left or right). | +| `Dg` | Dig in front of the turtle. | `side: string` - The tool side to use (left or right). | +| `Dgu` | Dig above the turtle. | `side: string` - The tool side to use (left or right). | +| `Dgd` | Dig below the turtle. | `side: string` - The tool side to use (left or right). | +| `S` | Suck items from in front of the turtle. | `count: number` - The number of items to suck. | +| `Su` | Suck items from above the turtle. | `count: number` - The number of items to suck. | +| `Sd` | Suck items from below the turtle. | `count: number` - The number of items to suck. | +| `Eqr` | Equip the selected item to the right side. | +| `Eql` | Equip the selected item to the left side. | +| `Sel` | Selects slot 1, or the specified slot. | `slot: number` - The slot to select. | +| `Dr` | Drops the selected items in front of the turtle. | `count: number` - The number of items to drop. | +| `Dru` | Drops the selected items above the turtle. | `count: number` - The number of items to drop. | +| `Drd` | Drops the selected items below the turtle. | `count: number` - The number of items to drop. | For example, if we want our turtle to go forward 3 times, instead of writing `turtle.forward()` 3 times, we can just do the following: @@ -67,6 +79,6 @@ The following snippets show a few example scripts, along with a description of w `3F2U1L` - Move forward 3 blocks, then up 2 blocks, and turn left. -`B2RAd` - Move back 2 blocks, then turn right twice, and then attack downward. +`B2RAd` - Move back, then turn right twice, and then attack downward. diff --git a/src/movescript.lua b/src/movescript.lua index 996da0e..054dfef 100644 --- a/src/movescript.lua +++ b/src/movescript.lua @@ -66,36 +66,144 @@ local function goDirection(dirFunction, digFunction, detectFunction, settings) end end -local function goUp(settings) +local function goUp(options, settings) debug("Moving up.", settings) goDirection(t.up, t.digUp, t.detectUp, settings) end -local function goDown(settings) +local function goDown(options, settings) debug("Moving down.", settings) goDirection(t.down, t.digDown, t.detectDown, settings) end -local function goForward(settings) +local function goForward(options, settings) debug("Moving forward.", settings) goDirection(t.forward, t.dig, t.detect, settings) end -local function goBack(settings) +local function goBack(options, settings) debug("Moving back.", settings) goDirection(t.back, t.digBack, t.detectBack, settings) end -local function goRight(settings) +local function goRight(options, settings) debug("Turning right.", settings) t.turnRight() end -local function goLeft(settings) +local function goLeft(options, settings) debug("Turning left.", settings) t.turnLeft() end +local function place(options, settings) + debug("Placing.", settings) + t.place(options.text) +end + +local function placeUp(options, settings) + debug("Placing up.", settings) + t.placeUp(options.text) +end + +local function placeDown(options, settings) + debug("Placing down.", settings) + t.placeDown(options.text) +end + +local function attack(options, settings) + debug("Attacking.", settings) + t.attack(options.side) +end + +local function attackUp(options, settings) + debug("Attacking up.", settings) + t.attackUp(options.side) +end + +local function attackDown(options, settings) + debug("Attacking down.", settings) + t.attackDown(options.side) +end + +local function dig(options, settings) + debug("Digging.", settings) + t.dig(options.side) +end + +local function digUp(options, settings) + debug("Digging up.", settings) + t.digUp(options.side) +end + +local function digDown(options, settings) + debug("Digging down.", settings) + t.digDown(options.side) +end + +local function suck(options, settings) + debug("Sucking.", settings) + local count = nil + if options.count ~= nil then + count = tonumber(options.count) + end + t.suck(count) +end + +local function suckUp(options, settings) + debug("Sucking up.", settings) + local count = nil + if options.count ~= nil then + count = tonumber(options.count) + end + t.suckUp(count) +end + +local function suckDown(options, settings) + debug("Sucking down.", settings) + local count = nil + if options.count ~= nil then + count = tonumber(options.count) + end + t.suckDown(count) +end + +local function selectSlot(options, settings) + local slot = 1 + if options.slot ~= nil then + slot = tonumber(options.slot) + end + debug("Selecting slot " .. slot .. ".", settings) + t.select(slot) +end + +local function drop(options, settings) + debug("Dropping.", settings) + local count = nil + if options.count ~= nil then + count = tonumber(options.count) + end + t.drop(count) +end + +local function dropUp(options, settings) + debug("Dropping up.", settings) + local count = nil + if options.count ~= nil then + count = tonumber(options.count) + end + t.dropUp(count) +end + +local function dropDown(options, settings) + debug("Dropping down.", settings) + local count = nil + if options.count ~= nil then + count = tonumber(options.count) + end + t.dropDown(count) +end + local actionMap = { ["U"] = {f = goUp, needsFuel = true}, ["D"] = {f = goDown, needsFuel = true}, @@ -103,12 +211,24 @@ local actionMap = { ["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} + ["P"] = {f = place, needsFuel = false}, + ["Pu"] = {f = placeUp, needsFuel = false}, + ["Pd"] = {f = placeDown, needsFuel = false}, + ["A"] = {f = attack, needsFuel = false}, + ["Au"] = {f = attackUp, needsFuel = false}, + ["Ad"] = {f = attackDown, needsFuel = false}, + ["Dg"] = {f = dig, needsFuel = false}, + ["Dgu"] = {f = digUp, needsFuel = false}, + ["Dgd"] = {f = digDown, needsFuel = false}, + ["S"] = {f = suck, needsFuel = false}, + ["Su"] = {f = suckUp, needsFuel = false}, + ["Sd"] = {f = suckDown, needsFuel = false}, + ["Eqr"] = {f = t.equipRight, needsFuel = false}, + ["Eql"] = {f = t.equipLeft, needsFuel = false}, + ["Sel"] = {f = selectSlot, needsFuel = false}, + ["Dr"] = {f = drop, needsFuel = false}, + ["Dru"] = {f = dropUp, needsFuel = false}, + ["Drd"] = {f = dropDown, needsFuel = false} } -- Tries to refuel the turtle from all slots that contain a valid fuel. @@ -155,19 +275,30 @@ 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) + if instruction.type == INSTRUCTION_TYPES.repeated then + debug("Executing repeated instruction " .. instruction.count .. " times.", settings) + for i = 1, instruction.count do + for _, nestedInstruction in pairs(instruction.instructions) do + executeInstruction(nestedInstruction, settings) + end + end + elseif instruction.type == INSTRUCTION_TYPES.instruction then + 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(instruction.options, settings) + end end - for i = 1, instruction.count do action.f() end end end @@ -281,6 +412,7 @@ function movescript.parse(script, settings) instruction.options = parseInstructionOptions(optionsText, settings) end end + if instruction.options == nil then instruction.options = {} end table.insert(instructions, instruction) scriptIdx = instructionMatchEndIdx + 1 else