CCCPaste

MangroveFarmer



local turtlePos, direction
local startPos, startDir

local function getGPSPosition()
    local x, y, z = gps.locate()
    if not x then print("Error: GPS not available") return nil end
    return {x = math.floor(x), y = math.floor(y), z = math.floor(z)}
end

local function negative(vec)
    return {x = -vec.x, y = -vec.y, z = -vec.z}
end

local function add(vec1, vec2)
    return {x = vec1.x + vec2.x, y = vec1.y + vec2.y, z = vec1.z + vec2.z}
end
local function sub(vec1, vec2)
    return add(vec1, negative(vec2))
end

local function multiply(s, vec)
    return {x = s * vec.x, y = s * vec.y, z = s * vec.z}
end

local function getSign(number)
    return number / math.abs(number)
end

local function isEqual(vec1, vec2)
    return vec1.x == vec2.x and vec1.y == vec2.y and vec1.z == vec2.z
end


-- === Basic Movement ===

local function moveForward()
    if turtle.forward() then
        turtlePos = add(turtlePos, direction)
        return true
    end
    return false
end
local function moveUp()
    if turtle.up() then
        turtlePos.y = turtlePos.y + 1
        return true
    end
    return false
end

local function moveDown()
    if turtle.down() then
        turtlePos.y = turtlePos.y - 1
        return true
    end
    return false
end

local function forceMoveForward()
    while not moveForward() do turtle.dig() end
end

local function forceMoveUp()
    while not moveUp() do turtle.digUp() end
end

local function forceMoveDown()
    while not moveDown() do turtle.digDown() end
end

-- === Basic Turning ===

local function turnInDirection(dir)
    if not direction then return end
    if dir == "left" then
        turtle.turnLeft()
        direction = {x = direction.z, y = 0, z = -direction.x}
    elseif dir == "right" then
        turtle.turnRight()
        direction = {x = -direction.z, y = 0, z = direction.x}
    elseif dir == "around" then
        turtle.turnLeft()
        turtle.turnLeft()
        direction = {x = -direction.x, y = 0, z = -direction.z}
    end
end

local function getTurnDirection(from, to)
    local function vectorsEqual(a, b)
        return a.x == b.x and a.z == b.z
    end

    if vectorsEqual(from, to) then return nil end
    local left  = {x = from.z, y = 0, z = -from.x}
    local right = {x = -from.z, y = 0, z = from.x}
    local back  = {x = -from.x, y = 0, z = -from.z}
    if vectorsEqual(to, left) then
        return "left"
    elseif vectorsEqual(to, right) then
        return "right"
    elseif vectorsEqual(to, back) then
        return "around"
    else
        error("Invalid target direction")
    end
end

local function getDirection()
    local pos1 = getGPSPosition()
    if not pos1 then error("GPS failure, cannot get direction") end

    for i = 1, 4 do
        if turtle.forward() then
            local pos2 = getGPSPosition()
            if not pos2 then error("GPS failure after move") end
            -- turtlePos = pos2
            -- Richtung berechnen
            direction = sub(pos2, pos1)

            -- zurück zur ursprünglichen Position
            turnInDirection("around")
            forceMoveForward()

            -- Sicherheitsprüfung
            local posBack = getGPSPosition()
            if not isEqual(pos1, posBack) then
                error("Warnung: Position hat sich beim Rückweg verschoben!")
                turtlePos = posBack -- explizit wieder auf GPS setzen
            else
                turtlePos = pos1
            end

            turnInDirection("around")
            return
        else
            turtle.turnLeft()
        end
    end

    error("Unable to move forward in any direction for direction detection")
end


-- === Positioning ===

local function goToPos(coord)
    local deltaX = coord.x - turtlePos.x
    local deltaY = coord.y - turtlePos.y
    local deltaZ = coord.z - turtlePos.z

    local dirX = startDir.x
    local dirZ = startDir.z

    local function moveToEqualX()
        while not (deltaX == 0) do
            turnInDirection(getTurnDirection(direction, {x = getSign(deltaX), y = 0, z = 0}))
            forceMoveForward()
            deltaX = coord.x - turtlePos.x
        end
    end

    local function moveToEqualZ()
        while not (deltaZ == 0) do
            turnInDirection(getTurnDirection(direction, {x = 0, y = 0, z = getSign(deltaZ)}))
            forceMoveForward()
            deltaZ = coord.z - turtlePos.z
        end
    end

    local function moveToEqualY()
        while not (deltaY == 0) do
            if deltaY > 0 then
                forceMoveUp()
            elseif deltaY < 0 then
                forceMoveDown()
            end
            deltaY = coord.y - turtlePos.y
        end
    end

    
    if dirX == 0 then
        moveToEqualZ()
        moveToEqualX()
    elseif dirZ == 0 then
        moveToEqualX()
        moveToEqualZ()
    end

    if not (deltaY == 0) then
        moveToEqualY()
        deltaX = coord.x - turtlePos.x
        deltaZ = coord.z - turtlePos.z
    end
end

local function goToStartOfTree()
    startTreePos = add(startPos, multiply(7, startDir))
    goToPos(startTreePos)
    turnInDirection(getTurnDirection(direction, startDir))
end

-- === Tasks ===

local function isSapling(item)
    if not item or not item.name then return false end

    local saplingSuffix = "_propagule"
    return item.name:match(":.*" .. saplingSuffix .. "$") ~= nil
end

local function isBoneMeal(item)
    if not item or not item.name then return false end
    return item.name == "minecraft:bone_meal"
end

local function isLog(item)
    if not item or not item.name then return false end

    local logSuffix = "_log"
    return item.name:match(":.*" .. logSuffix .. "$") ~= nil
end

local function getBoneMealCount()
    local num = 0
    for i = 1, 16 do
        local item = turtle.getItemDetail(i)
        
        if isBoneMeal(item) then
            num = num + turtle.getItemCount(i)
        end
    end
    return num
end

local function selectSaplingSlot()
    for i = 1, 16 do
        local item = turtle.getItemDetail(i)
        
        if isSapling(item) then
            turtle.select(i)
            return true
        end
    end
    return false
end

local function selectBoneMealSlot()
    for i = 1, 16 do
        local item = turtle.getItemDetail(i)
        
        if isBoneMeal(item) then
            turtle.select(i)
            return true
        end
    end
    return false
end

local function plantSapling()
    if not selectSaplingSlot() then return false end
    if not turtle.place() then return false end
    return true
end

local function fellBranch(bDown)
    -- if turtle goes down the tree
    bDown = bDown or false

    local suc, item = turtle.inspect()
    if not(suc and isLog(item)) then
        return false
    end
    if bDown then
        forceMoveDown()
        fellBranch()
        forceMoveUp()
    end

    branchDir = direction


    forceMoveForward()

    local function advanceInBranch()
        forceMoveForward()
        local suc, item = turtle.inspectUp()
        if suc and isLog(item) then
            forceMoveUp()
            advanceInBranch()
            forceMoveDown()
        end
        turnInDirection(getTurnDirection(direction, negative(branchDir)))
        forceMoveForward()
    end

    advanceInBranch()
    turnInDirection(getTurnDirection(direction, negative(branchDir)))
    forceMoveForward()
    turnInDirection(getTurnDirection(direction, branchDir))
    return true
end

local function fellTree()
    forceMoveForward()

    cnt = 0
    suc, item = turtle.inspectUp()
    while not (suc and isLog(item)) do
        forceMoveUp()
        suc, item = turtle.inspectUp()
        cnt = cnt + 1
        if cnt >= 25 then
            goToStartOfTree()
            return false
        end
    end

    forceMoveUp()
    startLogY = turtlePos.y

    fellBranch()

    suc, item = turtle.inspectUp()
    while suc and isLog(item) do
        forceMoveUp()
        fellBranch()
        suc, item = turtle.inspectUp()
    end

    endLogY = turtlePos.y

    turnInDirection("right")
    fellBranch(true)
    while not (turtlePos.y == startLogY) do
        forceMoveDown()
        fellBranch(true)
    end
    turnInDirection("right")
    fellBranch()
    while not (turtlePos.y == endLogY) do
        forceMoveUp()
        fellBranch()
    end
    turnInDirection("right")
    fellBranch(true)
    while not (turtlePos.y == startLogY) do
        forceMoveDown()
        fellBranch(true)
    end
    goToStartOfTree()

    return true
end



-- === Initialization ===

local function saveStartingParameters()
    local parameterList = {pos = turtlePos, dir = direction}

    local file = fs.open("startingParameters.txt", "w")
    file.write(textutils.serialize(parameterList))
    file.close()
end

local function loadStartingParameters()
    if not fs.exists("startingParameters.txt") then return false end

    local file = fs.open("startingParameters.txt", "r")
    local data = textutils.unserialize(file.readAll())

    file.close()

    startPos = data.pos
    startDir = data.dir
    return true
end

local function initProgram()
    turtlePos = getGPSPosition()
    if not turtlePos then error("GPS failure, cannot run the program") end
    
    getDirection()

    if not loadStartingParameters() then
        startPos = turtlePos
        startDir = direction
        saveStartingParameters()
    end
end



-- === Main ===

local function main()
    initProgram()
    goToStartOfTree()
    fellTree()
end

main()