SHOW:
|
|
- or go back to the newest paste.
| 1 | ---------------------------------------------------------------------- | |
| 2 | -- Master API -- | |
| 3 | ---------------------------------------------------------------------- | |
| 4 | - | |
| 4 | + | |
| 5 | - | -- Version 0.1 |
| 5 | + | -- Version 0.1(481): 1.481-compatible |
| 6 | - | |
| 6 | + | |
| 7 | -- Master is an API that controls modules that use my module API. | |
| 8 | -- Master should have: | |
| 9 | -- 1) fuel chest in the first slot. | |
| 10 | -- 2) stuff chest in the second slot | |
| 11 | -- 3) wireless mining turtle in the third slot | |
| 12 | -- 4) Any number of fuel/stuff chests and wireless mining turtles in its inventory | |
| 13 | -- 5) Note, that Master keeps at least one of each of those items in it's inventory. | |
| 14 | -- Master's job is to listen to requests and send responses. | |
| 15 | -- Usage: | |
| 16 | -- 1) For each type of the module you use, make a function which returns a response which will determine what module will do. | |
| 17 | -- This function recieves the ID of that module as an argument | |
| 18 | -- Of course, your module should know about that response and have that in its task table. | |
| 19 | -- You can use master.makeTask(taskName, coordinates, additionalData) function to generate a task response. | |
| 20 | -- additionalData parameter is optional, and if you don't want to send any coordinates, pass an empty table as coordinates. | |
| 21 | -- There is a master.makeReturnTask() function added for convinience - it just makes a task that returns module to the Master | |
| 22 | -- 2) Use master.setType(Type, taskFunction) function to associate that function with the type of the module | |
| 23 | -- you might want to change the state of the module in your taskFunction. Use master.getState(ID) and master.setState(ID, state) | |
| 24 | -- functions to do that. Initial state of each module is "Waiting" | |
| 25 | -- 4) Set navigation zones for modules using the master.setNavigation(x, z, height) function | |
| 26 | -- Please notice that x, z are 2D coordinates and height is the height of the plane where all the navigation is done | |
| 27 | - | -- 5) Initialize the master by running master.init(filename, ID, mainChannel, moduleCount) function |
| 27 | + | -- 5) Initialize the master by running master.init(filename, ID, moduleCount) function |
| 28 | -- Master should have module API on its disk and a script for modules (that's the filename argument) | |
| 29 | - | -- mainChannel is the channel on which master listens, and the moduleCount is the required amount of modules |
| 29 | + | -- moduleCount is the required amount of modules |
| 30 | -- ID is a new ID of the Master | |
| 31 | -- 6) make a stateFunction() that determines whether master should stop the operation. It should return false if it should stop | |
| 32 | -- and return true if it shouldn't. State function can do other things, such as reinitialization to a new module script and so on | |
| 33 | -- but it shouldn't take too much time to execute. Use master.reinit(filename, moduleCount) function to change the module script, if you want to. | |
| 34 | -- 7) Run master.operate(stateFunction) to start. | |
| 35 | ||
| 36 | -- Some basic variables: | |
| 37 | -- MasterID is the unique identifier of master. Default is 100 | |
| 38 | local MasterID = 100 | |
| 39 | ||
| 40 | - | -- Channel is the channel Master listens. |
| 40 | + | |
| 41 | - | local channel |
| 41 | + | |
| 42 | -- New placed modules will request "Position" to know where they are. | |
| 43 | local modPosition = {x = 1, y = 0, z = 0, f = 0}
| |
| 44 | ||
| 45 | -- naviZones is used by modules to navigate and not interlock themselves | |
| 46 | local naviZones = {x = 0, z = 0, height = 0}
| |
| 47 | function setNavigation (x, z, height) | |
| 48 | naviZones = {x = x, z = z, height = height}
| |
| 49 | end | |
| 50 | - | naviZones = {x = x, z = z, height = height}
|
| 50 | + | |
| 51 | --[[ | |
| 52 | ********************************************************************************************* | |
| 53 | * Communication Part * | |
| 54 | ********************************************************************************************* | |
| 55 | ]]-- | |
| 56 | ||
| 57 | rednet.open ("right")
| |
| 58 | ||
| 59 | - | -- We need a modem to communicate. |
| 59 | + | |
| 60 | - | local modem = peripheral.wrap ("right")
|
| 60 | + | |
| 61 | -- Message should be a table with fields | |
| 62 | -- 1) Protocol - must be equal to "KuuNet" | |
| 63 | -- 2) ID - that's a sender ID | |
| 64 | -- 3) Master - that must be equal to MasterID variable. | |
| 65 | -- 4) Type - the type of the module. Used to know how to handle its task requests | |
| 66 | -- Some other fields | |
| 67 | function isValid (message) | |
| 68 | if message ~= nil then | |
| 69 | if message.Protocol ~= "KuuNet" then | |
| 70 | return false | |
| 71 | - | if message ~= nil then |
| 71 | + | end |
| 72 | - | if message.Protocol ~= "KuuNet" then |
| 72 | + | if message.ID == nil then |
| 73 | - | return false |
| 73 | + | return false |
| 74 | - | end |
| 74 | + | end |
| 75 | - | if message.ID == nil then |
| 75 | + | if message.Master ~= MasterID then |
| 76 | - | return false |
| 76 | + | return false |
| 77 | - | end |
| 77 | + | end |
| 78 | - | if message.Master ~= MasterID then |
| 78 | + | return true |
| 79 | - | return false |
| 79 | + | else |
| 80 | - | end |
| 80 | + | return false |
| 81 | - | return true |
| 81 | + | end |
| 82 | - | else |
| 82 | + | |
| 83 | - | return false |
| 83 | + | |
| 84 | - | end |
| 84 | + | |
| 85 | function listen () | |
| 86 | while true do | |
| 87 | local event, sndID, text_msg, senderDistance = os.pullEvent("rednet_message")
| |
| 88 | local msg = textutils.unserialize (text_msg) | |
| 89 | - | while true do |
| 89 | + | if isValid(msg) then |
| 90 | - | local event, modemSide, sndChan, rplyChan, text_msg, senderDistance = os.pullEvent("modem_message")
|
| 90 | + | return msg |
| 91 | - | local msg = textutils.unserialize (text_msg) |
| 91 | + | end |
| 92 | - | if isValid(msg) then |
| 92 | + | end |
| 93 | - | return msg |
| 93 | + | |
| 94 | - | end |
| 94 | + | |
| 95 | - | end |
| 95 | + | |
| 96 | function response (ID, message) | |
| 97 | message.Protocol = "KuuNet" | |
| 98 | message.ID = ID | |
| 99 | - | function response (ID, chan, message) |
| 99 | + | message.Master = MasterID |
| 100 | - | message.Protocol = "KuuNet" |
| 100 | + | rednet.broadcast (textutils.serialize(message)) |
| 101 | - | message.ID = ID |
| 101 | + | |
| 102 | - | message.Master = MasterID |
| 102 | + | |
| 103 | - | modem.transmit (chan+1, chan, textutils.serialize(message)) |
| 103 | + | |
| 104 | ********************************************************************************************* | |
| 105 | * Module Placement Part * | |
| 106 | ********************************************************************************************* | |
| 107 | ]]-- | |
| 108 | -- moduleCount is the number of active modules | |
| 109 | -- needModules is the number of modules required | |
| 110 | -- modulesAvailable is the number of available modules | |
| 111 | local moduleCount = 0 | |
| 112 | local needModules = 0 | |
| 113 | local modAvailable = nil | |
| 114 | -- This function searches the turtle inventory for same item | |
| 115 | -- as in the given slot, or selects that slot if there are more than one item | |
| 116 | function searchItem (slot) | |
| 117 | turtle.select (slot) | |
| 118 | local found = 0 | |
| 119 | for i=1,16 do | |
| 120 | - | turtle.select (slot) |
| 120 | + | if i ~= slot then |
| 121 | - | local found = 0 |
| 121 | + | if turtle.getItemCount (i) > 0 then |
| 122 | - | for i=1,16 do |
| 122 | + | if turtle.compareTo (i) then |
| 123 | - | if i ~= slot then |
| 123 | + | found = i |
| 124 | - | if turtle.getItemCount (i) > 0 then |
| 124 | + | end |
| 125 | - | if turtle.compareTo (i) then |
| 125 | + | end |
| 126 | - | found = i |
| 126 | + | end |
| 127 | - | end |
| 127 | + | end |
| 128 | - | end |
| 128 | + | if found == 0 then |
| 129 | - | end |
| 129 | + | if turtle.getItemCount (slot) > 1 then |
| 130 | - | end |
| 130 | + | found = slot |
| 131 | - | if found == 0 then |
| 131 | + | else |
| 132 | - | if turtle.getItemCount (slot) > 1 then |
| 132 | + | turtle.select(1) |
| 133 | - | found = slot |
| 133 | + | return false |
| 134 | - | else |
| 134 | + | end |
| 135 | - | turtle.select(1) |
| 135 | + | end |
| 136 | - | return false |
| 136 | + | turtle.select (found) |
| 137 | - | end |
| 137 | + | return true |
| 138 | - | end |
| 138 | + | |
| 139 | - | turtle.select (found) |
| 139 | + | |
| 140 | - | return true |
| 140 | + | |
| 141 | turtle.select (slot) | |
| 142 | local count = 0 | |
| 143 | for i = 1,16 do | |
| 144 | - | turtle.select (slot) |
| 144 | + | if turtle.compareTo(i) then |
| 145 | - | local count = 0 |
| 145 | + | count = count + turtle.getItemCount(i) |
| 146 | - | for i = 1,16 do |
| 146 | + | end |
| 147 | - | if turtle.compareTo(i) then |
| 147 | + | end |
| 148 | - | count = count + turtle.getItemCount(i) |
| 148 | + | return count |
| 149 | - | end |
| 149 | + | |
| 150 | - | end |
| 150 | + | |
| 151 | - | return count |
| 151 | + | |
| 152 | -- The counting takes some time, so there is a variable to speed up the process | |
| 153 | function availableModules () | |
| 154 | if modAvailable == nil then | |
| 155 | local minimum = 1024 | |
| 156 | for i = 1, 3 do | |
| 157 | - | if modAvailable == nil then |
| 157 | + | local quantity = countBySample(i) - 1 |
| 158 | - | local minimum = 1024 |
| 158 | + | if minimum > quantity then |
| 159 | - | for i = 1, 3 do |
| 159 | + | minimum = quantity |
| 160 | - | local quantity = countBySample(i) - 1 |
| 160 | + | end |
| 161 | - | if minimum > quantity then |
| 161 | + | end |
| 162 | - | minimum = quantity |
| 162 | + | modAvailable = minimum |
| 163 | - | end |
| 163 | + | end |
| 164 | - | end |
| 164 | + | return modAvailable |
| 165 | - | modAvailable = minimum |
| 165 | + | |
| 166 | - | end |
| 166 | + | |
| 167 | - | return modAvailable |
| 167 | + | |
| 168 | searchItem (3) -- search for a module | |
| 169 | if turtle.place () then -- put it down | |
| 170 | searchItem (1) | |
| 171 | - | searchItem (3) -- search for a module |
| 171 | + | turtle.drop (1) -- Add a fuel chest |
| 172 | - | if turtle.place () then -- put it down |
| 172 | + | searchItem (2) |
| 173 | - | searchItem (1) |
| 173 | + | turtle.drop (1) -- And a stuff chest |
| 174 | - | turtle.drop (1) -- Add a fuel chest |
| 174 | + | turtle.select (1)-- select first slot to make things look good :) |
| 175 | - | searchItem (2) |
| 175 | + | peripheral.call ("front", "turnOn") -- Turn on the module
|
| 176 | - | turtle.drop (1) -- And a stuff chest |
| 176 | + | modAvailable = modAvailable - 1 |
| 177 | - | turtle.select (1)-- select first slot to make things look good :) |
| 177 | + | end |
| 178 | - | peripheral.call ("front", "turnOn") -- Turn on the module
|
| 178 | + | |
| 179 | - | modAvailable = modAvailable - 1 |
| 179 | + | |
| 180 | - | end |
| 180 | + | |
| 181 | ********************************************************************************************* | |
| 182 | * Operation Part * | |
| 183 | ********************************************************************************************* | |
| 184 | ]]-- | |
| 185 | ||
| 186 | -- This is a table that contains all the states of the modules. | |
| 187 | -- Indexes of that table are ID's and values are tables with following fields | |
| 188 | -- 1) Type - type of the module. Each Type has it's own task table | |
| 189 | -- 2) State - the state of the module. List of states is unique for each module type, but there are some common states: "Waiting" and "Returning" | |
| 190 | tStates = {}
| |
| 191 | ||
| 192 | -- There is a function that searches for a free ID. Let's limit the maximun number of IDs to 1024 | |
| 193 | function freeID () | |
| 194 | - | |
| 194 | + | for i = 1, 1024 do |
| 195 | if tStates [i] == nil then | |
| 196 | return i | |
| 197 | - | for i = 1, 1024 do |
| 197 | + | end |
| 198 | - | if tStates [i] == nil then |
| 198 | + | end |
| 199 | - | return i |
| 199 | + | |
| 200 | - | end |
| 200 | + | |
| 201 | - | end |
| 201 | + | |
| 202 | tTasks = {}
| |
| 203 | ||
| 204 | -- Here is the table used to handle the requests. | |
| 205 | tRequests = {
| |
| 206 | -- "Master" is the request sent by new modules. We should assign a new ID to it and remember that ID in tStates table | |
| 207 | Master = function (request) | |
| 208 | local ID = freeID () | |
| 209 | - | -- "Master" is the request sent by new modules. We should assign a new ID to it and remember that ID in tStates table |
| 209 | + | response (request.ID, {NewID = ID})
|
| 210 | - | Master = function (request) |
| 210 | + | tStates[ID] = {State = "Waiting", Type = request.Type}
|
| 211 | - | local ID = freeID () |
| 211 | + | moduleCount = moduleCount + 1 |
| 212 | - | response (request.ID, channel, {NewID = ID})
|
| 212 | + | end, |
| 213 | - | tStates[ID] = {State = "Waiting", Type = request.Type}
|
| 213 | + | -- Task is the request used to reques the next thing module should do |
| 214 | - | moduleCount = moduleCount + 1 |
| 214 | + | -- It uses the tTasks table. There is a function for each module type which returns a response |
| 215 | - | end, |
| 215 | + | -- Response may contain coordinate of the next place and id should contain "Task" field |
| 216 | - | -- Task is the request used to reques the next thing module should do |
| 216 | + | -- This function may do something else, change the state of module and so on. |
| 217 | - | -- It uses the tTasks table. There is a function for each module type which returns a response |
| 217 | + | -- To associate it with the module, sender ID is passed to that function |
| 218 | - | -- Response may contain coordinate of the next place and id should contain "Task" field |
| 218 | + | -- tTasks table should be filled by user of this API |
| 219 | - | -- This function may do something else, change the state of module and so on. |
| 219 | + | Task = function (request) |
| 220 | - | -- To associate it with the module, sender ID is passed to that function |
| 220 | + | response (request.ID, tTasks[request.Type](request.ID)) |
| 221 | - | -- tTasks table should be filled by user of this API |
| 221 | + | end, |
| 222 | - | Task = function (request) |
| 222 | + | -- "Returned" is the request sent by module that has returned to Master and waiting there until Master collects it |
| 223 | - | response (request.ID, channel, tTasks[request.Type](request.ID)) |
| 223 | + | Returned = function (request) |
| 224 | - | end, |
| 224 | + | while turtle.suck () do end -- Get all the items that module had |
| 225 | - | -- "Returned" is the request sent by module that has returned to Master and waiting there until Master collects it |
| 225 | + | turtle.dig () -- And get the module back |
| 226 | - | Returned = function (request) |
| 226 | + | tStates[request.ID] = nil -- delete that module from our state table |
| 227 | - | while turtle.suck () do end -- Get all the items that module had |
| 227 | + | moduleCount = moduleCount - 1 -- and decrease the counter |
| 228 | - | turtle.dig () -- And get the module back |
| 228 | + | modAvailable = modAvailable + 1 |
| 229 | - | tStates[request.ID] = nil -- delete that module from our state table |
| 229 | + | end |
| 230 | - | moduleCount = moduleCount - 1 -- and decrease the counter |
| 230 | + | |
| 231 | - | modAvailable = modAvailable + 1 |
| 231 | + | |
| 232 | - | end |
| 232 | + | -- This is the variable used to determine whether the master should place modules |
| 233 | local isPlacing = false | |
| 234 | ||
| 235 | - | -- This is the variable used to determine whether the master should place modules |
| 235 | + | |
| 236 | -- It automatically stops placing modules when there is enough modules | |
| 237 | function moduleManager () | |
| 238 | while true do | |
| 239 | if isPlacing then | |
| 240 | if moduleCount == needModules or availableModules() == 0 then | |
| 241 | - | while true do |
| 241 | + | isPlacing = false |
| 242 | - | if isPlacing then |
| 242 | + | else |
| 243 | - | if moduleCount == needModules or availableModules() == 0 then |
| 243 | + | addModule () |
| 244 | - | isPlacing = false |
| 244 | + | end |
| 245 | - | else |
| 245 | + | end |
| 246 | - | addModule () |
| 246 | + | sleep (6) |
| 247 | - | end |
| 247 | + | end |
| 248 | - | end |
| 248 | + | |
| 249 | - | sleep (6) |
| 249 | + | |
| 250 | - | end |
| 250 | + | |
| 251 | -- stateFunction is the function used to determine when master should stop. | |
| 252 | -- Master stops when there are to active modules and stateFunction returns false. | |
| 253 | -- State function can do other things, such as reinitialization to a new module script and so on, but it shouldn't take too much time to execute | |
| 254 | function operate (stateFunction) | |
| 255 | local server = function () | |
| 256 | while stateFunction() or moduleCount > 0 do | |
| 257 | local request = listen () | |
| 258 | - | local server = function () |
| 258 | + | tRequests[request.Request](request) -- Just execute the request handler. |
| 259 | - | while stateFunction() or moduleCount > 0 do |
| 259 | + | end |
| 260 | - | local request = listen () |
| 260 | + | end |
| 261 | - | tRequests[request.Request](request) -- Just execute the request handler. |
| 261 | + | parallel.waitForAny (server, moduleManager) |
| 262 | - | end |
| 262 | + | rednet.close ("right")
|
| 263 | - | end |
| 263 | + | |
| 264 | - | parallel.waitForAny (server, moduleManager) |
| 264 | + | |
| 265 | - | modem.closeAll () |
| 265 | + | |
| 266 | ********************************************************************************************* | |
| 267 | * Initialization Part * | |
| 268 | ********************************************************************************************* | |
| 269 | ]]-- | |
| 270 | ||
| 271 | -- Some basic movement and refueling | |
| 272 | -- Refuel assumes that Master has a bunch of fuel chests in slot 1 and slot 16 is empty | |
| 273 | function refuel (amount) | |
| 274 | if turtle.getFuelLevel () > amount then | |
| 275 | return true | |
| 276 | else | |
| 277 | - | if turtle.getFuelLevel () > amount then |
| 277 | + | turtle.select (1) |
| 278 | - | return true |
| 278 | + | turtle.placeUp () |
| 279 | - | else |
| 279 | + | turtle.select (16) |
| 280 | - | turtle.select (1) |
| 280 | + | turtle.suckUp () |
| 281 | - | turtle.placeUp () |
| 281 | + | while turtle.refuel (1) do |
| 282 | - | turtle.select (16) |
| 282 | + | if turtle.getFuelLevel() >= amount then |
| 283 | - | turtle.suckUp () |
| 283 | + | turtle.dropUp () |
| 284 | - | while turtle.refuel (1) do |
| 284 | + | turtle.select (1) |
| 285 | - | if turtle.getFuelLevel() >= amount then |
| 285 | + | turtle.digUp () |
| 286 | - | turtle.dropUp () |
| 286 | + | return true |
| 287 | - | turtle.select (1) |
| 287 | + | end |
| 288 | - | turtle.digUp () |
| 288 | + | if turtle.getItemCount (1) == 0 then |
| 289 | - | return true |
| 289 | + | turtle.suckUp () |
| 290 | - | end |
| 290 | + | end |
| 291 | - | if turtle.getItemCount (1) == 0 then |
| 291 | + | end |
| 292 | - | turtle.suckUp () |
| 292 | + | end |
| 293 | - | end |
| 293 | + | turtle.dropUp () |
| 294 | - | end |
| 294 | + | turtle.select (1) |
| 295 | - | end |
| 295 | + | turtle.digUp () |
| 296 | - | turtle.dropUp () |
| 296 | + | return false |
| 297 | - | turtle.select (1) |
| 297 | + | |
| 298 | - | turtle.digUp () |
| 298 | + | |
| 299 | - | return false |
| 299 | + | |
| 300 | forward = turtle.forward, | |
| 301 | back = turtle.back | |
| 302 | } | |
| 303 | - | forward = turtle.forward, |
| 303 | + | |
| 304 | - | back = turtle.back |
| 304 | + | refuel (1) |
| 305 | while not tMoves[direction]() do | |
| 306 | print "Movement obstructed. Waiting" | |
| 307 | - | refuel (1) |
| 307 | + | sleep (1) |
| 308 | - | while not tMoves[direction]() do |
| 308 | + | end |
| 309 | - | print "Movement obstructed. Waiting" |
| 309 | + | |
| 310 | - | sleep (1) |
| 310 | + | |
| 311 | - | end |
| 311 | + | |
| 312 | function setType (Type, taskFunction) | |
| 313 | tTasks[Type] = taskFunction | |
| 314 | end | |
| 315 | ||
| 316 | - | tTasks[Type] = taskFunction |
| 316 | + | |
| 317 | -- Filename is the name of module's script. It will be copied on the disk drive | |
| 318 | function init (filename, ID, moduleCount) | |
| 319 | -- Set the ID of the Master | |
| 320 | MasterID = ID | |
| 321 | - | function init (filename, ID, mainChannel, moduleCount) |
| 321 | + | |
| 322 | - | -- Set the ID of the Master |
| 322 | + | -- Next, we need to know the position of the master. |
| 323 | - | MasterID = ID |
| 323 | + | -- If gps is not found, use relative coordinates |
| 324 | - | -- Set the main channel and listen on said channel |
| 324 | + | local gpsPresent = true |
| 325 | - | channel = mainChannel |
| 325 | + | local x, y, z = gps.locate(5) |
| 326 | - | modem.open (channel) |
| 326 | + | if x == nil then |
| 327 | - | |
| 327 | + | x, y, z = 0, 0, 0 |
| 328 | - | -- Next, we need to know the position of the master. |
| 328 | + | gpsPresent = false |
| 329 | - | -- If gps is not found, use relative coordinates |
| 329 | + | end |
| 330 | - | modem.open(gps.CHANNEL_GPS) |
| 330 | + | |
| 331 | - | local gpsPresent = true |
| 331 | + | -- Now we need to move forward to copy files on disk and determine our f |
| 332 | - | local x, y, z = gps.locate(5) |
| 332 | + | forceMove ("forward")
|
| 333 | - | if x == nil then |
| 333 | + | local newX, newZ = 1, 0 -- if there is no gps, assume that master is facing positive x |
| 334 | - | x, y, z = 0, 0, 0 |
| 334 | + | if gpsPresent then |
| 335 | - | gpsPresent = false |
| 335 | + | newX, __, newZ = gps.locate (5) |
| 336 | - | end |
| 336 | + | end |
| 337 | -- Determine f by the difference of coordinates. | |
| 338 | - | -- Now we need to move forward to copy files on disk and determine our f |
| 338 | + | local xDiff = newX - x |
| 339 | - | forceMove ("forward")
|
| 339 | + | local zDiff = newZ - z |
| 340 | - | local newX, newZ = 1, 0 -- if there is no gps, assume that master is facing positive x |
| 340 | + | if xDiff ~= 0 then |
| 341 | - | if gpsPresent then |
| 341 | + | if xDiff > 0 then |
| 342 | - | newX, __, newZ = gps.locate (5) |
| 342 | + | f = 0 -- Positive x |
| 343 | - | end |
| 343 | + | else |
| 344 | - | modem.close(gps.CHANNEL_GPS) |
| 344 | + | f = 2 -- Negative x |
| 345 | - | -- Determine f by the difference of coordinates. |
| 345 | + | end |
| 346 | - | local xDiff = newX - x |
| 346 | + | else |
| 347 | - | local zDiff = newZ - z |
| 347 | + | if zDiff > 0 then |
| 348 | - | if xDiff ~= 0 then |
| 348 | + | f = 1 -- Positive z |
| 349 | - | if xDiff > 0 then |
| 349 | + | else |
| 350 | - | f = 0 -- Positive x |
| 350 | + | f = 3 -- Negative z |
| 351 | - | else |
| 351 | + | end |
| 352 | - | f = 2 -- Negative x |
| 352 | + | end |
| 353 | - | end |
| 353 | + | -- And set the position and modPosition variables. |
| 354 | - | else |
| 354 | + | Position = {x = x, y = y, z = z, f = f}
|
| 355 | - | if zDiff > 0 then |
| 355 | + | modPosition = {x = newX, y = y, z = newZ, f = f}
|
| 356 | - | f = 1 -- Positive z |
| 356 | + | |
| 357 | - | else |
| 357 | + | -- Copy all the required files on the disk |
| 358 | - | f = 3 -- Negative z |
| 358 | + | if fs.exists ("/disk/module") then
|
| 359 | - | end |
| 359 | + | fs.delete ("/disk/module")
|
| 360 | - | end |
| 360 | + | end |
| 361 | - | -- And set the position and modPosition variables. |
| 361 | + | fs.copy ("module", "/disk/module")
|
| 362 | - | Position = {x = x, y = y, z = z, f = f}
|
| 362 | + | if fs.exists ("/disk/"..filename) then
|
| 363 | - | modPosition = {x = newX, y = y, z = newZ, f = f}
|
| 363 | + | fs.delete ("/disk/"..filename)
|
| 364 | end | |
| 365 | - | -- Copy all the required files on the disk |
| 365 | + | fs.copy (filename, "/disk/"..filename) |
| 366 | - | if fs.exists ("/disk/module") then
|
| 366 | + | -- Make a startup file for modules |
| 367 | - | fs.delete ("/disk/module")
|
| 367 | + | local file = fs.open ("/disk/startup", "w")
|
| 368 | - | end |
| 368 | + | file.writeLine ("shell.run(\"copy\", \"/disk/module\", \"/module\")")
|
| 369 | - | fs.copy ("module", "/disk/module")
|
| 369 | + | file.writeLine ("shell.run(\"copy\", \"/disk/"..filename.."\", \"/startup\")")
|
| 370 | - | if fs.exists ("/disk/"..filename) then
|
| 370 | + | file.writeLine ("shell.run(\"startup\")")
|
| 371 | - | fs.delete ("/disk/"..filename)
|
| 371 | + | file.close() |
| 372 | - | end |
| 372 | + | |
| 373 | - | fs.copy (filename, "/disk/"..filename) |
| 373 | + | -- Now, make a file with the data modules need |
| 374 | - | -- Make a startup file for modules |
| 374 | + | file = fs.open ("/disk/initdata", "w")
|
| 375 | - | local file = fs.open ("/disk/startup", "w")
|
| 375 | + | -- Communication data: master ID and communication channel |
| 376 | - | file.writeLine ("shell.run(\"copy\", \"/disk/module\", \"/module\")")
|
| 376 | + | file.writeLine (textutils.serialize ({MasterID = MasterID, channel = channel}) )
|
| 377 | - | file.writeLine ("shell.run(\"copy\", \"/disk/"..filename.."\", \"/startup\")")
|
| 377 | + | -- Location data: |
| 378 | - | file.writeLine ("shell.run(\"startup\")")
|
| 378 | + | file.writeLine (textutils.serialize (modPosition)) |
| 379 | - | file.close() |
| 379 | + | -- Navigation data: |
| 380 | - | |
| 380 | + | file.writeLine (textutils.serialize (naviZones)) |
| 381 | - | -- Now, make a file with the data modules need |
| 381 | + | file.close() |
| 382 | - | file = fs.open ("/disk/initdata", "w")
|
| 382 | + | |
| 383 | - | -- Communication data: master ID and communication channel |
| 383 | + | -- And go back to initial location |
| 384 | - | file.writeLine (textutils.serialize ({MasterID = MasterID, channel = channel}) )
|
| 384 | + | forceMove ("back")
|
| 385 | - | -- Location data: |
| 385 | + | |
| 386 | - | file.writeLine (textutils.serialize (modPosition)) |
| 386 | + | -- Set the amount of modules needed. I use "+" because one can run init again to add a different type of module to the operation |
| 387 | - | -- Navigation data: |
| 387 | + | needModules = needModules + moduleCount |
| 388 | - | file.writeLine (textutils.serialize (naviZones)) |
| 388 | + | -- And start placing them |
| 389 | - | file.close() |
| 389 | + | isPlacing = true |
| 390 | - | |
| 390 | + | |
| 391 | - | -- And go back to initial location |
| 391 | + | |
| 392 | - | forceMove ("back")
|
| 392 | + | |
| 393 | --[[ | |
| 394 | - | -- Set the amount of modules needed. I use "+" because one can run init again to add a different type of module to the operation |
| 394 | + | |
| 395 | - | needModules = needModules + moduleCount |
| 395 | + | |
| 396 | - | -- And start placing them |
| 396 | + | |
| 397 | - | isPlacing = true |
| 397 | + | |
| 398 | ||
| 399 | - | |
| 399 | + | |
| 400 | - | |
| 400 | + | |
| 401 | -- return position is two block away of Master. So, let's calculate it. | |
| 402 | local tShifts = {
| |
| 403 | [0] = { 1, 0},
| |
| 404 | [1] = { 0, 1},
| |
| 405 | [2] = {-1, 0},
| |
| 406 | [3] = { 0, -1},
| |
| 407 | } | |
| 408 | local xShift, zShift = unpack (tShifts[modPosition.f]) | |
| 409 | - | -- return position is two block away of Master. So, let's calculate it. |
| 409 | + | returnX = modPosition.x + xShift |
| 410 | - | local tShifts = {
|
| 410 | + | returnZ = modPosition.z + zShift |
| 411 | - | [0] = { 1, 0},
|
| 411 | + | return { Task = "Return",
|
| 412 | - | [1] = { 0, 1},
|
| 412 | + | x = returnX, |
| 413 | - | [2] = {-1, 0},
|
| 413 | + | y = modPosition.y, |
| 414 | - | [3] = { 0, -1},
|
| 414 | + | z = returnZ, |
| 415 | - | } |
| 415 | + | f = (modPosition.f+2)%4, -- basically, reverse direction |
| 416 | - | local xShift, zShift = unpack (tShifts[modPosition.f]) |
| 416 | + | } |
| 417 | - | returnX = modPosition.x + xShift |
| 417 | + | |
| 418 | - | returnZ = modPosition.z + zShift |
| 418 | + | |
| 419 | - | return { Task = "Return",
|
| 419 | + | |
| 420 | - | x = returnX, |
| 420 | + | |
| 421 | - | y = modPosition.y, |
| 421 | + | |
| 422 | - | z = returnZ, |
| 422 | + | local newTask = {Task = taskName}
|
| 423 | - | f = (modPosition.f+2)%4, -- basically, reverse direction |
| 423 | + | for key, value in pairs (coordinates) do |
| 424 | - | } |
| 424 | + | newTask[key] = value |
| 425 | end | |
| 426 | - | |
| 426 | + | if additionalData ~= nil then |
| 427 | for key, value in pairs (additionalData) do | |
| 428 | newTask[key] = value | |
| 429 | end | |
| 430 | - | local newTask = {Task = taskName}
|
| 430 | + | end |
| 431 | - | for key, value in pairs (coordinates) do |
| 431 | + | return newTask |
| 432 | - | newTask[key] = value |
| 432 | + | |
| 433 | - | end |
| 433 | + | |
| 434 | - | if additionalData ~= nil then |
| 434 | + | |
| 435 | - | for key, value in pairs (additionalData) do |
| 435 | + | return tStates[ID].State |
| 436 | - | newTask[key] = value |
| 436 | + | |
| 437 | - | end |
| 437 | + | |
| 438 | - | end |
| 438 | + | |
| 439 | - | return newTask |
| 439 | + | tStates[ID].State = newState |
| 440 | end | |
| 441 | - | |
| 441 | + | |
| 442 | -- reinit function is just a simplified init, that doesn't update channel, MasterID and Master's position. Use it to change the modules script | |
| 443 | - | return tStates[ID].State |
| 443 | + | |
| 444 | forceMove ("forward")
| |
| 445 | - | |
| 445 | + | -- Copy all the required files on the disk |
| 446 | if fs.exists ("/disk/module") then
| |
| 447 | - | tStates[ID].State = newState |
| 447 | + | fs.delete ("/disk/module")
|
| 448 | end | |
| 449 | fs.copy ("module", "/disk/module")
| |
| 450 | if fs.exists ("/disk/"..filename) then
| |
| 451 | fs.delete ("/disk/"..filename)
| |
| 452 | - | forceMove ("forward")
|
| 452 | + | end |
| 453 | - | -- Copy all the required files on the disk |
| 453 | + | fs.copy (filename, "/disk/"..filename) |
| 454 | - | if fs.exists ("/disk/module") then
|
| 454 | + | -- Make a startup file for modules |
| 455 | - | fs.delete ("/disk/module")
|
| 455 | + | local file = fs.open ("/disk/startup", "w")
|
| 456 | - | end |
| 456 | + | file.writeLine ("shell.run(\"copy\", \"/disk/module\", \"/module\")")
|
| 457 | - | fs.copy ("module", "/disk/module")
|
| 457 | + | file.writeLine ("shell.run(\"copy\", \"/disk/"..filename.."\", \"/startup\")")
|
| 458 | - | if fs.exists ("/disk/"..filename) then
|
| 458 | + | file.writeLine ("shell.run(\"startup\")")
|
| 459 | - | fs.delete ("/disk/"..filename)
|
| 459 | + | file.close() |
| 460 | - | end |
| 460 | + | |
| 461 | - | fs.copy (filename, "/disk/"..filename) |
| 461 | + | -- Now, make a file with the data modules need |
| 462 | - | -- Make a startup file for modules |
| 462 | + | file = fs.open ("/disk/initdata", "w")
|
| 463 | - | local file = fs.open ("/disk/startup", "w")
|
| 463 | + | -- Communication data: master ID |
| 464 | - | file.writeLine ("shell.run(\"copy\", \"/disk/module\", \"/module\")")
|
| 464 | + | file.writeLine (textutils.serialize ({MasterID = MasterID}) )
|
| 465 | - | file.writeLine ("shell.run(\"copy\", \"/disk/"..filename.."\", \"/startup\")")
|
| 465 | + | -- Location data: |
| 466 | - | file.writeLine ("shell.run(\"startup\")")
|
| 466 | + | file.writeLine (textutils.serialize (modPosition)) |
| 467 | - | file.close() |
| 467 | + | -- Navigation data: |
| 468 | - | |
| 468 | + | file.writeLine (textutils.serialize (naviZones)) |
| 469 | - | -- Now, make a file with the data modules need |
| 469 | + | file.close() |
| 470 | - | file = fs.open ("/disk/initdata", "w")
|
| 470 | + | |
| 471 | - | -- Communication data: master ID and communication channel |
| 471 | + | -- And go back to initial location |
| 472 | - | file.writeLine (textutils.serialize ({MasterID = MasterID, channel = channel}) )
|
| 472 | + | forceMove ("back")
|
| 473 | - | -- Location data: |
| 473 | + | |
| 474 | - | file.writeLine (textutils.serialize (modPosition)) |
| 474 | + | -- Set the amount of modules needed. I use "+" because one can run init again to add a different type of module to the operation |
| 475 | - | -- Navigation data: |
| 475 | + | needModules = needModules + moduleCount |
| 476 | - | file.writeLine (textutils.serialize (naviZones)) |
| 476 | + | -- And start placing them |
| 477 | - | file.close() |
| 477 | + | isPlacing = true |
| 478 | - | |
| 478 | + |