Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- os.loadAPI('apis.lua')
- Peripheral.wrap("wireless_modem")
- local args = { ... }
- local options = {
- chunks = { arg = 'c', type = 'number', value = -1,
- desc = 'Number of chunks to mine' },
- depth = { arg = 'd', type = 'number', value = 9000,
- desc = 'Mining depth' },
- plug = { arg = 'f', type = 'flag', value = false,
- desc = 'Fill in top hole' },
- logMethod = { arg = 'l', type = 'string', value = 'wireless',
- desc = 'Logging: file, screen' },
- help = { arg = 'h', type = 'flag', value = false,
- desc = 'Displays the options' }
- }
- local miners = {}
- local pickupQueue = {}
- local workQueue = {}
- local miningStatus = {
- fuel = 0,
- activity = nil,
- count = 0,
- version = 'v1.3a',
- prompt = 'm for menu'
- }
- local mining = {
- status = 'idle',
- firstTurtle,
- diameter = 1,
- chunkIndex = 0,
- chunks = -1,
- depth = 9000,
- holes = 0,
- plug = false
- }
- function getChunkCoordinates(diameter, index, x, y)
- local dirs = { -- circumference of grid
- { xd = 0, yd = 1, heading = 1 }, -- south
- { xd = -1, yd = 0, heading = 2 },
- { xd = 0, yd = -1, heading = 3 },
- { xd = 1, yd = 0, heading = 0 } -- east
- }
- -- always move east when entering the next diameter
- if index == 0 then
- dirs[4].x = x + 16
- dirs[4].y = y
- return dirs[4]
- end
- dir = dirs[math.floor(index / (diameter - 1)) + 1]
- dir.x = x + dir.xd * 16
- dir.y = y + dir.yd * 16
- return dir
- end
- function getChunkLoadedBox()
- local ax, ay = getCornerOf(TL2.getNamedLocation('chunkborder'))
- if TL2.getNamedLocation('chunkloader1') then
- ax, ay = getCornerOf(TL2.getNamedLocation('chunkloader1'))
- end
- local bx, by = getCornerOf(TL2.getNamedLocation('chunkloader2'))
- local boundingBox = {
- ax = math.min(ax, bx),
- ay = math.min(ay, by),
- bx = math.max(ax, bx)+15,
- by = math.max(ay, by)+15
- }
- return boundingBox
- end
- function getBoreLocations(x, y)
- local locations = {}
- while true do
- local a = math.abs(y)
- local b = math.abs(x)
- if x > 0 and y > 0 or
- x < 0 and y < 0 then
- -- rotate coords
- a = math.abs(x)
- b = math.abs(y)
- end
- if (a % 5 == 0 and b % 5 == 0) or
- (a % 5 == 2 and b % 5 == 1) or
- (a % 5 == 4 and b % 5 == 2) or
- (a % 5 == 1 and b % 5 == 3) or
- (a % 5 == 3 and b % 5 == 4) then
- table.insert(locations, { x = x, y = y })
- end
- if y % 2 == 0 then -- forward dir
- if (x + 1) % 16 == 0 then
- y = y + 1
- else
- x = x + 1
- end
- else
- if (x - 1) % 16 == 15 then
- if (y + 1) % 16 == 0 then
- break
- end
- y = y + 1
- else
- x = x - 1
- end
- end
- end
- return locations
- end
- -- get the bore location closest to the miner
- local function getClosestLocation(points, b)
- local key = 1
- local distance = 9000
- for k,a in pairs(points) do
- -- try and avoid floating point operation
- local d = math.max(a.x, b.x) - math.min(a.x, b.x) +
- math.max(a.y, b.y) - math.min(a.y, b.y)
- if d < distance then
- d = math.sqrt(
- math.pow(a.x - b.x, 2) + math.pow(a.y - b.y, 2))
- if d < distance then
- key = k
- distance = d
- if distance <= 1 then
- break
- end
- end
- end
- end
- return table.remove(points, key)
- end
- function getCornerOf(c)
- return math.floor(c.x / 16) * 16, math.floor(c.y / 16) * 16
- end
- function showSetup(message)
- message = message or ''
- errorPage.message = message
- UI.pager:setPage('error')
- end
- function releaseMiners()
- if mining.status ~= 'mining' then -- chunk loaders are already placed if mining
- local chunkloadersNeeded = 2
- if TL2.getNamedLocation('chunkloader1') then
- chunkloadersNeeded = 1
- end
- if TL2.getNamedLocation('chunkloader2') then
- chunkloadersNeeded = chunkloadersNeeded - 1
- end
- if turtle.getItemCount(1) < chunkloadersNeeded then
- showSetup('Not enough chunk loaders in slot 1')
- return false
- end
- end
- local maxMiners = turtle.getItemCount(2)
- if maxMiners == 0 then
- showSetup('No ender chests in slot 2')
- end
- if not mining.firstTurtle then
- local firstTurtle
- if maxMiners == 1 then
- for i = 16, 3, -1 do
- if turtle.getItemCount(i) == 1 then
- firstTurtle = i
- break
- end
- end
- else
- for i = 3, 16 do
- local itemCount = turtle.getItemCount(i)
- if itemCount == 0 then
- break
- end
- if itemCount > 1 then
- if itemCount < maxMiners then
- maxMiners = itemCount
- end
- else
- firstTurtle = i
- break
- end
- end
- end
- if not firstTurtle then
- showSetup('No turtles found in inventory')
- return false
- end
- Logger.log('miningBoss', 'firstTurtle: ' .. firstTurtle)
- Logger.log('miningBoss', 'maxMiners: ' .. maxMiners)
- -- check resources
- local minerCount = 0
- for i = firstTurtle, 16 do
- if turtle.getItemCount(i) == 1 then
- minerCount = minerCount + 1
- end
- end
- Logger.log('miningBoss', 'minerCount: ' .. minerCount)
- if minerCount > maxMiners then
- for i = 3, firstTurtle-1 do
- if turtle.getItemCount(i) == maxMiners then
- showSetup('Not enough resources in slot ' .. i)
- return false
- end
- end
- end
- -- sanity checking
- for i = firstTurtle, 16 do
- if turtle.getItemCount(i) > 1 then
- showSetup('Invalid setup')
- return false
- end
- end
- mining.firstTurtle = firstTurtle
- end
- for i = mining.firstTurtle, 16 do
- if turtle.getItemCount(i) == 1 then
- queueWork(51, 'releaseMiner-' .. i, 'releaseMiner', { slot = i })
- end
- end
- return true
- end
- function updateStatus(miner, status)
- local function getIndicator(value, past)
- local ind = ' '
- if past then
- if value > past then
- ind = '^'
- elseif value < past then
- ind = 'v'
- end
- end
- return ind
- end
- miner.statusD = miner.xStatus
- if miner.xStatus ~= 'deployed' then
- miner.statusD = miner.xStatus
- if miner.xStatus == 'pickup' then
- miner.statusD = 'pkup'
- end
- end
- if not miner.lastFuel then
- miner.lastFuel = miner.fuel
- end
- miner.fuelD = string.format("%s%dk",
- getIndicator(math.floor(miner.fuel/1024), math.floor(miner.lastFuel/1024)),
- math.floor(miner.fuel/1024))
- miner.lastFuel = miner.fuel
- miner.depthD = string.format("%s%d",
- getIndicator(status.z, miner.lastLocation.z),
- status.z)
- miner.lastLocation = miner.location
- miner.coordsD = string.format("%d,%d", status.x, status.y)
- miner.timestamp = os.clock()
- local timer = Event.getNamedTimer('statusTimer')
- if not timer or not Event.isTimerActive(timer) then
- Event.addNamedTimer('statusTimer', 1, false, function()
- if statusPage.enabled then
- statusPage:draw()
- end
- end)
- end
- end
- function releaseMiner(slot)
- if mining.status ~= 'mining' then
- return true
- end
- showActivity('Releasing miner')
- local x, y = getCornerOf(TL2.getNamedLocation('chunkloader2'), 16, 16, 1)
- local box = TL2.pointToBox({ x = x, y = y, z = 0 }, 16, 16, 1)
- while true do
- local deployPt = TL2.createPoint(TL2.getState())
- deployPt.x = deployPt.x - 2
- deployPt.y = deployPt.y - 2
- local deployBox = TL2.pointToBox(deployPt, 4, 4, 1)
- TL2.boxContain(box, deployBox)
- if not TL2.pointInBox(TL2.getState(), deployBox) or TL2.isTurtleAt('bottom') then
- local r = Util.random(15)
- TL2.goto(deployBox.ax + math.floor(r / 4), deployBox.ay + r % 4, 0)
- end
- if not turtle.detectDown() then
- break
- end
- if not TL2.isTurtleAt('bottom') and TL2.digDown() then
- break
- end
- end
- if turtle.getItemCount(slot) ~= 1 then
- showActivity('Not a turtle')
- return true
- end
- for i = 2, mining.firstTurtle - 1 do
- if turtle.getItemCount(i) == 0 then
- showActivity('Not enough resources')
- return true
- end
- end
- -- place miner
- if not TL2.placeDown(slot) then
- -- someone took out a turtle from the inventory :(
- return true
- end
- os.sleep(.1)
- -- give miner resources
- for i = 2, mining.firstTurtle - 1 do
- TL2.select(i)
- turtle.dropDown(1)
- end
- peripheral.call('bottom', 'turnOn')
- if not Util.tryTimed(5,
- function()
- local id = peripheral.call('bottom', 'getID')
- if id then
- local pt = TL2.createPoint(TL2.getState())
- pt.heading = TL2.getState().heading
- miners[id] = {
- id = id,
- status = 'idle',
- xStatus = 'new',
- deployLocation = pt,
- location = pt,
- lastLocation = pt,
- name = 'turtle_' .. tostring(id)
- }
- TLC.requestState(id)
- return true
- end
- os.sleep(.1)
- return false
- end) then
- -- turtle won't start or this is not a turtle
- TL2.select(slot)
- turtle.digDown()
- end
- --pager:setPage('status')
- return true
- end
- TLC.registerAction('releaseMiner', function(args)
- return releaseMiner(args.slot)
- end)
- function collectMiner(miner)
- showActivity('Picking up turtle')
- if not TL2.pointInBox(miner.location, getChunkLoadedBox()) then
- shutdownCommand(miner)
- Logger.log('miningBoss', 'shutting down ' .. miner.id .. ' too far away')
- return true
- end
- TL2.goto(miner.location.x, miner.location.y, 0)
- if not TL2.isTurtleAt('bottom') then
- queueWork(3, 'rescue-' .. miner.id, 'rescueMiner', miner)
- --[[
- Logger.log('shutting down ' .. miner.id .. ' unable to locate')
- TLC.sendAction(miner.id, 'shutdown', location)
- miners[miner.id] = nil
- --]]
- return true
- end
- local id = peripheral.call('bottom', 'getID')
- if id and miners[id] then
- local miner = miners[id]
- local slots = TL2.getInventory()
- for i = 2, mining.firstTurtle-1 do
- TL2.select(i)
- if turtle.suckDown() then
- slots[i].qty = slots[i].qty + 1
- end
- end
- TL2.reconcileInventory(slots)
- local slot = TL2.selectOpenSlot(3)
- miners[miner.id] = nil
- if not slot then
- -- too many turtles for inventory
- peripheral.call('bottom', 'shutdown')
- Logger.log('miningBoss', 'shutting down ' .. id .. ' no room')
- elseif turtle.digDown() then
- if mining.status == 'mining' and miner.fuel > 1024 then
- -- check to see if we mined up something other than a turtle
- if turtle.getItemCount(slot) == 1 then
- releaseMiner(slot)
- end
- end
- end
- UI.pager:getCurrentPage():draw()
- if Util.size(miners) == 0 then
- UI.pager:setPage('menu')
- local chunks = math.pow(mining.diameter-2, 2) + mining.chunkIndex
- if mining.status == 'recalling' and
- mining.chunks ~= -1 and
- chunks >= mining.chunks then
- -- automatically exit if we exceeded requested diameter
- Event.exitPullEvents()
- end
- end
- end
- return true
- end
- function setStatus(status)
- mining.status = status
- showActivity()
- end
- function showActivity(currentActivity)
- if currentActivity then
- miningStatus.activity = currentActivity
- Logger.log('miningBoss', currentActivity)
- else
- miningStatus.activity = mining.status
- end
- miningStatus.count = Util.size(miners)
- if UI.pager:getCurrentPage().statusBar then
- UI.pager:getCurrentPage().statusBar:draw()
- end
- end
- optionsPage = UI.Page({
- titleBar = UI.TitleBar({
- title = 'Mining Options',
- previousPage = true
- }),
- form = UI.Form({
- fields = {
- { label = 'Chunks', key = 'chunks',display = UI.Form.D.entry, limit = 4,
- help = 'Number of chunks to mine' },
- { label = 'Depth', key = 'depth', display = UI.Form.D.entry, limit = 3,
- help = 'Leave blank for unlimited' },
- { label = 'Fill top hole', key = 'plug', display = UI.Form.D.chooser,
- choices = {
- { name = 'No', value = 'n' },
- { name = 'Yes', value = 'y' },
- },
- width = 7, help = '' },
- { text = 'Accept', event = 'accept', display = UI.Form.D.button,
- x = 5, y = 5, width = 10 },
- { text = 'Cancel', event = 'cancel', display = UI.Form.D.button,
- x = 19, y = 5, width = 10 }
- },
- labelWidth = 18,
- valueWidth = UI.term.width-18,
- x = 5,
- y = 4,
- height = UI.term.height-4
- }),
- statusBar = UI.StatusBar()
- })
- function optionsPage:enable()
- local t = {
- plug = 'n',
- depth = '',
- chunks = '',
- }
- if mining.plug then
- t.plug = 'y'
- end
- if mining.depth ~= 9000 then
- t.depth = tostring(mining.depth)
- end
- if mining.chunks ~= -1 then
- t.chunks = tostring(mining.chunks)
- end
- self.form:setValues(t)
- self:focusFirst()
- end
- function optionsPage:eventHandler(event)
- if event.type == 'focus_change' then
- self.statusBar:setStatus(event.focused.help)
- self.statusBar:draw()
- elseif event.type == 'cancel' then
- UI.pager:setPreviousPage()
- elseif event.type == 'accept' then
- local values = self.form.values
- values.chunks = tonumber(values.chunks)
- if not values.chunks or not tonumber(values.chunks) then
- values.chunks = -1
- end
- values.depth = tonumber(values.depth)
- if not values.depth or not tonumber(values.depth) then
- values.depth = 9000
- end
- if values.plug == 'Y' or values.plug == 'y' then
- values.plug = true
- else
- values.plug = false
- end
- mining.depth = values.depth
- mining.chunks = values.chunks
- mining.plug = values.plug
- UI.pager:setPreviousPage()
- end
- return UI.Page.eventHandler(self, event)
- end
- --[[ -- menuPage -- ]]--
- menuPage = UI.Page({
- titleBar = UI.TitleBar({
- title = 'Turtle Mining Swarm ' .. miningStatus.version
- }),
- menu = UI.Menu({
- centered = true,
- y = 4,
- width = UI.term.width,
- menuItems = {
- { prompt = 'Deploy Miners', event = 'deploy' },
- { prompt = 'Options', event = 'options' },
- { prompt = 'Stop mining', event = 'stop' },
- { prompt = 'Status', event = 'status' },
- { prompt = 'Help', event = 'help' },
- { prompt = 'Quit', event = 'quit' }
- }
- }),
- --[[
- progressWindow = UI.Window({
- x = UI.term.width - 20,
- y = 3,
- width = 18,
- height = 9,
- backgroundColor = colors.blue,
- totalHolesProgressBar = UI.VerticalMeter({
- y = 7,
- x = 2,
- height = 8
- }),
- chunkHolesProgressBar = UI.VerticalMeter({
- y = 10,
- x = 2,
- height = 8
- }),
- }),
- --]]
- statusBar = UI.StatusBar({
- columns = {
- { '', 'activity', UI.term.width - 13 },
- { '', 'fuel', 10 }
- },
- status = miningStatus
- })
- })
- function menuPage:enable()
- local fuel = turtle.getFuelLevel()
- if fuel > 9999 then
- miningStatus.fuel = string.format('Fuel: %dk', math.floor(fuel/1000))
- else
- miningStatus.fuel = 'Fuel: ' .. turtle.getFuelLevel()
- end
- end
- function menuPage:eventHandler(event)
- if event.type == 'deploy' then
- if releaseMiners() then
- setStatus('mining')
- UI.pager:setPage('status')
- if not TL2.getNamedLocation('chunkloader2') then
- TL2.gotoNamedLocation('chunkborder')
- TL2.placeUp(1)
- TL2.saveNamedLocation('chunkloader2', 0, 0, 0)
- Message.broadcast('alive')
- end
- end
- elseif event.type == 'options' then
- UI.pager:setPage('options')
- elseif event.type == 'stop' then
- if mining.status == 'mining' then
- UI.pager:setPage('status')
- setStatus('recalling')
- end
- elseif event.type == 'status' then
- UI.pager:setPage('status')
- elseif event.type == 'help' then
- showSetup()
- elseif event.type == 'quit' then
- Event.exitPullEvents()
- return true
- end
- return UI.Page.eventHandler(self, event)
- end
- --[[ -- statusPage -- ]]--
- statusPage = UI.Page({
- grid = UI.Grid({
- columns = {
- { 'Name', 'name', 13 },
- { 'Fuel', 'fuelD', 5 },
- { 'Depth', 'depthD', 6 },
- --{ 'Coords', 'coordsD', 6 },
- { 'Time', 'timeD', 5 },
- { '', 'statusD', 4 }
- },
- sortColumn = 'name',
- pageSize = 11,
- width = UI.term.width,
- t = miners,
- sizeMethod = 'count'
- }),
- statusBar = UI.StatusBar({
- columns = {
- { '', 'activity', UI.term.width - 13 },
- { '', 'prompt', 10 }
- },
- --backgroundColor = colors.blue,
- status = miningStatus
- })
- })
- function statusPage:eventHandler(event)
- if event.type == 'key' then
- if event.key == 'm' or event.key == 'q' or event.key == 'enter' then
- UI.pager:setPage('menu')
- return true
- end
- end
- return self.grid:eventHandler(event)
- end
- function statusPage:draw()
- for _,miner in pairs(miners) do
- if miner.timestamp then
- miner.timeD =
- string.format("%ds",
- math.floor(os.clock()-miner.timestamp))
- end
- end
- self.grid:draw()
- self.statusBar:draw()
- end
- --[[-- errorPage --]]--
- errorPage = UI.Page({
- titleBar = UI.TitleBar({
- title = 'Configuration'
- }),
- window = UI.Window({
- y = 2,
- height = UI.term.height -1,
- backgroundColor = colors.blue,
- focus = function() end
- })
- })
- function errorPage:draw()
- self.titleBar:draw()
- self.window:draw()
- self.window:setCursorPos(1, 1)
- self.window:print(self.message)
- self.window:setCursorPos(1, 3)
- self.window:print('Slot 1: 2 chunk loaders')
- self.window:print('Slot 2: ender chests ')
- self.window:print('Slot 3 through x: resources that should not be mined')
- self.window:print('Place turtles in the remainder of the slots immediately following the resources')
- self.window:print('')
- self.window:print('Press any key to continue')
- end
- function errorPage:eventHandler(event)
- if event.type == 'key' then
- UI.pager:setPage('menu')
- end
- end
- -- tell the miner to unload chest, go to pickup plane and report when ready
- function pickupCommand(miner)
- if miner.xStatus ~= 'pickup' then
- TLC.sendActions(miner.id, {
- { action = 'enderChestUnload', args = { slots = mining.firstTurtle-2 }},
- { action = 'gotoZ', args = {
- z = 0, digStrategy = 'cautious', mode = 'destructive' }},
- { action = 'status' }
- })
- miner.xStatus = 'pickup'
- end
- end
- function shutdownCommand(miner)
- miners[miner.id] = nil
- TLC.sendActions(miner.id, {
- { action = 'enderChestUnload', args = { slots = mining.firstTurtle-2 }},
- { action = 'shutdown' }
- })
- end
- function transferFuelCommand(miner)
- TLC.sendActions(miner.id, {
- { action = 'gotoZ', args = {
- z = 0, digStrategy = 'cautious', mode = 'destructive' }},
- { action = 'transferFuel' }
- })
- end
- function boreCommand(miner)
- local bore = getClosestLocation(mining.locations,
- miner.location)
- mining.holes = mining.holes + 1 -- for status monitor only
- miner.location.x = bore.x
- miner.location.y = bore.y
- miner.xStatus = 'busy'
- local actions = {
- { action = 'gotoZ', args = {
- z = -1, -- make sure he is on the correct plane
- digStrategy = 'cautious',
- mode = 'destructive' }},
- { action = 'plug', args = {
- plug = mining.plug }},
- { action = 'goto', args = {
- x = bore.x, y = bore.y, z = -1,
- digStrategy = 'cautious',
- mode = 'destructive' }},
- { action = 'gotoZ', args = {
- z = -2,
- digStrategy = 'cautious',
- mode = 'destructive' }},
- { action = 'bore', args = {
- depth = mining.depth }},
- { action = 'status' }
- }
- TLC.sendActions(miner.id, actions)
- saveState()
- end
- TLC.registerAction('refuelFromMiner', function(miner)
- local slot = TL2.selectOpenSlot()
- if slot and TL2.pointInBox(miner.location, getChunkLoadedBox()) then
- showActivity('Refueling')
- TL2.goto(miner.location.x, miner.location.y)
- transferFuelCommand(miner)
- Event.waitForEvent('turtle_inventory', 3)
- turtle.select(slot)
- turtle.refuel(64)
- if menuPage.enabled then
- menuPage:draw()
- end
- end
- return true
- end)
- TLC.registerAction('rescueMiner', function(miner)
- --if miner.xStatus ~= 'lost' then
- --return true
- --end
- local distance
- Util.tryTimes(5, function()
- Message.send(miner.id, 'alive')
- _,_,_,distance = Message.waitForMessage('isAlive', 1, miner.id)
- return distance
- end)
- if not distance then
- if not miner.retryCount then
- miner.retryCount = 0
- end
- miner.retryCount = miner.retryCount + 1
- if miner.retryCount > 3 then
- shutdownCommand(miner)
- Logger.log('miningBoss', 'shutting down ' .. miner.id .. ' unable to locate')
- else
- queueWork(3, 'rescue-' .. miner.id, 'rescueMiner', miner)
- end
- return true
- end
- local boundingBox = getChunkLoadedBox()
- showActivity('Rescuing turtle')
- --pager:setPage('status')
- local location = TLC.tracker(miner.id, distance, true, boundingBox)
- if location then
- -- miners start out 1 below boss plane
- location.z = - location.z + 1
- TLC.sendAction(miner.id, 'setLocation', location)
- end
- if not location or (args.fuel == 0 and location.z ~= 0) then
- -- not in a place we can pick up (don't want to leave plane)
- shutdownCommand(miner)
- Logger.log('miningBoss', 'shutting down ' .. miner.id .. ' no fuel or too far away')
- else
- miner.xStatus = 'lost'
- pickupCommand(miner)
- end
- UI.pager:getCurrentPage():draw()
- Message.broadcast('alive')
- return true
- end)
- Message.addHandler('turtleStatus', function(h, id, msg, distance)
- local status = msg.contents
- --Logger.log(string.format('%d %s', id, status.status))
- local miner = miners[id]
- --if miner then
- --Logger.log('xstatus: ' .. miner.xStatus)
- --end
- if not miner then
- Message.send(id, 'alive')
- if mining.status ~= 'mining' or status.status ~= 'idle' then
- return
- end
- miners[id] = {
- id = id,
- xStatus = 'lost',
- lastLocation = { x = 0, y = 0, z = 0 }
- }
- miner = miners[id]
- if status.x == 0 and status.y == 0 and status.z == 0 then
- queueWork(3, 'rescue-' .. miner.id, 'rescueMiner', miner)
- elseif TL2.pointInBox(status, getChunkLoadedBox()) then
- miner.name = tostring(status.name)
- miner.status = status.status
- miner.fuel = status.fuel
- miner.location = { x = status.x, y = status.y, z = status.z }
- pickupCommand(miner)
- return
- else
- queueWork(3, 'rescue-' .. miner.id, 'rescueMiner', miner)
- end
- end
- miner.name = tostring(status.name)
- miner.status = status.status
- miner.fuel = status.fuel
- miner.location = { x = status.x, y = status.y, z = status.z }
- if miner.xStatus == 'new' then
- -- just deployed
- TLC.sendAction(id, 'setLocation', miner.deployLocation)
- miner.location = miner.deployLocation
- miner.xStatus = 'deployed' -- needed ?? shouldn't it be 'idle'
- end
- if miner.xStatus == 'lost' then
- -- ignore
- elseif miner.xStatus == 'pickup' then
- if not pickupQueue[miner.id] then
- pickupQueue[miner.id] = miner
- queueWork(50, 'checkMiners', 'checkMiners')
- end
- elseif miner.status == 'idle' then
- if mining.status == 'recalling' then
- pickupCommand(miner)
- elseif mining.status == 'mining' and TL2.getState().status == 'idle' then
- if msg.contents.fuel > 1024 then
- if #mining.locations == 0 then
- if not isQueued('moveChunkLoaders') then
- queueWork(75, 'moveChunkLoaders', 'moveChunkLoaders')
- end
- else
- if turtle.getFuelLevel() < 15000 and status.reserveFuel > 0 then
- TLC.performAction('refuelFromMiner', miner)
- end
- boreCommand(miner)
- end
- else
- Logger.log('miningBoss', 'miner ' .. miner.id .. ' low fuel')
- pickupCommand(miner)
- end
- end
- end
- updateStatus(miner, status)
- --Logger.log('end xstatus: ' .. miner.xStatus)
- end)
- function placeChunkLoader(direction, x, y, heading)
- if direction == 'up' then
- TL2.goto(x, y, 0)
- TL2.placeUp(1)
- TL2.saveNamedLocation('chunkloader1', x, y, 0)
- else
- TL2.goto(x, y, 0, heading)
- TL2.up()
- TL2.place(1)
- TL2.down()
- local heading = TL2.getHeadingInfo()
- TL2.saveNamedLocation('chunkloader2',
- x + heading.xd, y + heading.yd, 0)
- end
- end
- function collectChunkLoaders()
- showActivity('Collecting chunk loaders')
- if TL2.gotoNamedLocation('chunkloader1') then
- TL2.emptySlot(1)
- TL2.select(1)
- turtle.digUp()
- end
- if TL2.gotoNamedLocation('chunkloader2') then
- TL2.select(1)
- turtle.digUp()
- end
- showActivity()
- end
- function outsideBox(c, box)
- return c.x < box.ax or c.y < box.ay or c.x > box.bx or c.y > box.by
- end
- function collectChunkLoader(namedLocation)
- local c = TL2.getNamedLocation(namedLocation)
- if c then
- local cb = TL2.getNamedLocation('chunkborder')
- local b = { ax = cb.x, ay = cb.y, bx = cb.x + 15, by = cb.y + 15 }
- if outsideBox(c, b) then
- local x, y = c.x, c.y
- if c.x < cb.x then
- x = math.max(c.x, cb.x)
- elseif c.x > cb.x+15 then
- x = math.min(c.x, cb.x+15)
- end
- if c.y < cb.y then
- y = math.max(c.y, cb.y)
- elseif c.y > cb.y+15 then
- y = math.min(c.y, cb.y+15)
- end
- TL2.goto(x, y)
- TL2.headTowards(c)
- TL2.up()
- TL2.select(1)
- turtle.dig()
- TL2.down()
- else
- TL2.gotoPoint(c)
- TL2.select(1)
- turtle.digUp()
- end
- end
- end
- TLC.registerAction('setLocation', function()
- Logger.log('miningBoss', 'ignoring set location')
- return true
- end)
- -- rise above to eliminate the rednet deadzone
- TLC.registerAction('gps', function()
- -- become a mini-gps
- Message.broadcast('alive')
- local x, y = getCornerOf(TL2.getNamedLocation('chunkborder'))
- local function broadcastPosition()
- local pt = TL2.createPoint(TL2.getState())
- pt.z = pt.z + 1
- Message.broadcast('position', pt)
- end
- TL2.goto(x + 8, y + 5, 86)
- -- drop down a couple of blocks in case we hit a bedrock roof (nether)
- TL2.gotoZ(TL2.getState().z - 4)
- local z = TL2.getState().z
- broadcastPosition()
- TL2.goto(x + 8, y + 11, z)
- broadcastPosition()
- TL2.goto(x + 5, y + 8, z-1)
- broadcastPosition()
- TL2.goto(x + 11, y + 8, z-1)
- broadcastPosition()
- queueWork(2, 'descend', 'descend')
- mining.status = 'mining'
- return true
- end)
- TLC.registerAction('descend', function()
- if TL2.getState().z ~= 0 then
- local x, y = getCornerOf(TL2.getNamedLocation('chunkborder'))
- TL2.goto(x + 8, y + 8, 0)
- end
- return true
- end)
- TLC.registerAction('moveChunkLoaders', function()
- showActivity('Moving chunk loaders')
- local x, y = getCornerOf(TL2.getNamedLocation('chunkborder'))
- local points = math.pow(mining.diameter, 2) - math.pow(mining.diameter-2, 2)
- mining.chunkIndex = mining.chunkIndex + 1
- if mining.chunkIndex >= points then
- mining.diameter = mining.diameter + 2
- mining.chunkIndex = 0
- end
- if mining.chunks ~= -1 then
- local chunks = math.pow(mining.diameter-2, 2) + mining.chunkIndex
- if chunks >= mining.chunks then
- setStatus('recalling')
- return true
- end
- end
- local nc = getChunkCoordinates(mining.diameter, mining.chunkIndex, x, y)
- local cl1 = { x = x + nc.xd * 15, y = y + nc.yd * 15 }
- local cl2 = { x = x + nc.xd * 15, y = y + nc.yd * 15 }
- -- brute force calculations
- if nc.heading == 0 then
- cl1.y = cl1.y + 1
- elseif nc.heading == 1 then
- cl1.x = cl1.x + 1
- elseif nc.heading == 2 then
- cl1.x = nc.x + 16
- cl1.y = nc.y
- cl2.x = nc.x + 16
- cl2.y = nc.y + 1
- elseif nc.heading == 3 then
- cl1.x = nc.x + 15
- cl1.y = nc.y + 16
- cl2.x = nc.x + 14
- cl2.y = nc.y + 16
- end
- -- collect prev chunk's loader
- collectChunkLoader('chunkloader1')
- local ocl = TL2.getNamedLocation('chunkloader2')
- if cl1.x == ocl.x and cl1.y == ocl.y then
- -- turning a corner - no need to move 2nd chunk loader
- TL2.saveNamedLocation('chunkloader1', cl1.x, cl1.y, 0)
- else
- -- place at edge of loaded chunk
- -- now 2 in chunk
- placeChunkLoader('up', cl1.x, cl1.y)
- -- get the first one
- collectChunkLoader('chunkloader2')
- end
- -- place in next chunk
- placeChunkLoader('front', cl2.x, cl2.y, nc.heading)
- mining.locations = getBoreLocations(nc.x, nc.y)
- -- enter next chunk
- TL2.gotoPoint(TL2.getNamedLocation('chunkloader2'))
- TL2.saveNamedLocation('chunkborder', nc.x, nc.y, 0, 0)
- queueWork(50, 'checkMiners', 'checkMiners')
- return true
- end)
- -- clear state every time we move
- -- if the server shuts down during movement, we cannot resume
- -- 99.9% of the time, we should be idle
- TLC.registerAction('clearState', function()
- fs.delete('mining.state')
- return true
- end)
- TLC.actionChainStart('clearState')
- function saveState()
- local state = TL2.getState()
- mining.x = state.x
- mining.y = state.y
- mining.heading = state.heading
- mining.namedLocations = TL2.getMemory().locations
- fs.delete('mining.state')
- Util.writeTable('mining.state', mining)
- end
- TLC.registerAction('saveState', function()
- saveState()
- showActivity()
- return true
- end)
- TLC.actionChainEnd('saveState')
- TLC.registerAction('checkMiners', function()
- local chunkborder = TL2.getNamedLocation('chunkborder')
- -- pickup any that are ready
- if Util.size(pickupQueue) > 0 then
- if TL2.selectOpenSlot(3) or mining.status == 'recalling' then
- for _,miner in pairs(pickupQueue) do
- -- pickup any miners in the deployment location
- if miner.location.x == chunkborder.x and miner.location.y == chunkborder.y then
- miner.distance = 0
- else
- miner.distance = TL2.calculateDistance(TL2.getState(), miner.location)
- end
- end
- local k,miner = Util.first(pickupQueue,
- function(a,b) return a.distance < b.distance end)
- table.remove(pickupQueue, k)
- collectMiner(miner)
- queueWork(50, 'checkMiners', 'checkMiners')
- return true
- end
- end
- return true
- end)
- Message.addHandler('getMiningStatus', function(h, id, msg)
- Message.send(id, 'miningStatus', { state = mining, status = miningStatus })
- end)
- function enableWirelessLogging()
- Message.broadcast('logClient')
- local _, id = Message.waitForMessage('logServer', 1)
- if not id then
- return false
- end
- Logger.setWirelessLogging(id)
- return true
- end
- function resume()
- if not fs.exists('mining.state') then
- return false
- end
- local tmining = Util.readTable('mining.state')
- if not tmining.namedLocations or
- not tmining.x or
- Util.size(tmining.namedLocations) == 0 then
- return false
- end
- local state = TL2.getState()
- state.x = tmining.x
- state.y = tmining.y
- state.heading = tmining.heading
- TL2.getMemory().locations = tmining.namedLocations
- mining = tmining
- miningStatus.activity = 'Resuming mining'
- -- release any miners that we did not release previously
- if mining.status == 'mining' then
- --releaseMiners()
- UI.pager:setPage('status')
- end
- queueWork(1, 'gps', 'gps')
- mining.status = 'resuming'
- return true
- end
- function getWork()
- local k,work = Util.first(workQueue, function(a,b) return a.priority < b.priority end)
- if k then
- workQueue[k] = nil
- return work
- end
- end
- Event.addHandler('workReady', function()
- if TL2.getState().status ~= 'idle' then
- Logger.log('miningBoss', 'busy')
- Event.queueTimedEvent('endTimer', 2.5, 'workReady')
- return
- end
- Logger.log('miningBoss', 'Queue size: ' .. Util.size(workQueue))
- local work = getWork()
- if work then
- TLC.performAction(work.action, work.actionArgs)
- if Util.size(workQueue) > 0 then
- Event.queueTimedEvent('endTimer', 2.5, 'workReady')
- end
- end
- end)
- function isQueued(name)
- return workQueue[name]
- end
- function queueWork(priority, name, action, actionArgs)
- if not workQueue[name] then
- workQueue[name] = {
- priority = priority,
- name = name,
- action = action,
- actionArgs = actionArgs
- }
- end
- Event.queueTimedEvent('endTimer', 2.5, 'workReady')
- Logger.log('miningBoss', 'Queuing: ' .. name)
- end
- TL2.setMode('destructive')
- TL2.setDigStrategy('wasteful')
- UI.pager:setPages({
- [ 'menu' ] = menuPage,
- [ 'status' ] = statusPage,
- [ 'options' ] = optionsPage,
- [ 'error' ] = errorPage
- })
- if not Util.getOptions(options, args) then
- return
- end
- mining.depth = options.depth.value
- mining.chunks = options.chunks.value
- mining.plug = options.plug.value
- if turtle.getFuelLevel() < 1000 then
- error('Add at least 1000 fuel before starting')
- end
- Logger.disable()
- UI.pager:setPage('menu')
- if not resume() then
- -- set the reference plane to 2 above deployment location
- TL2.getState().z = -2
- TL2.saveNamedLocation('chunkborder', 0, 0, 0, 0)
- mining.locations = getBoreLocations(0, 0)
- end
- Logger.filter('event', 'rednet_send', 'rednet_receive', 'debug')
- if options.logMethod.value == 'wireless' then
- Message.enableWirelessLogging()
- elseif options.logMethod.value == 'file' then
- Logger.setFileLogging('mine.log')
- elseif options.logMethod.value == 'screen' then
- Logger.setScreenLogging()
- end
- TLC.pullEvents('miningBoss')
- fs.delete('mining.state')
- collectChunkLoaders()
- TL2.gotoZ(-2)
- --TL2.goto(0, 0, -2, 0)
- UI.term:reset()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement