SHOW:
|
|
- or go back to the newest paste.
1 | SLOT_CROPS = 1 | |
2 | SLOT_ANALYSER = 2 | |
3 | SLOT_SEEDS = 3 | |
4 | ||
5 | ACTIVATOR_PULSE_DURATION = 1 | |
6 | ||
7 | -- Interval at which the turtle checks if a plant has matured (in seconds) | |
8 | MATURE_SLEEP_DURATION = 5 | |
9 | SPREAD_SLEEP_DURATION = 5 | |
10 | ANALYSE_SLEEP_DURATION = 1 -- interval for which to check if analyse process is finsished | |
11 | ||
12 | -- If "true", excess non-10/10/10 seeds will get trashed | |
13 | TRASH_EXCESS_SEEDS = true | |
14 | ||
15 | -- the seed analyser uses absolute facing directions, adjust these depending on your setup | |
16 | ANALYSER_LOWER_FACE = "WEST" | |
17 | ANALYSER_UPPER_FACE = "EAST" | |
18 | ||
19 | STATE_NORMAL = "normal" | |
20 | STATE_ALTERNATE = "alternate" | |
21 | ||
22 | CROP_LOWER_RIGHT = { x = 2, y = 1 } | |
23 | CROP_LOWER_LEFT = { x = 1, y = 1 } | |
24 | CROP_UPPER_RIGHT = { x = 2, y = 2 } | |
25 | CROP_UPPER_LEFT = { x = 1, y = 2 } | |
26 | ||
27 | ANALYSER_LOWER_RIGHT = { x = 2, y = 0 } | |
28 | ANALYSER_LOWER_LEFT = { x = 1, y = 0 } | |
29 | ANALYSER_UPPER_RIGHT = { x = 2, y = 3 } | |
30 | ANALYSER_UPPER_LEFT = { x = 1, y = 3 } | |
31 | ||
32 | ACTIVATOR_LOWER_RIGHT = { x = 3, y = 1 } | |
33 | ACTIVATOR_LOWER_LEFT = { x = 0, y = 1 } | |
34 | ACTIVATOR_UPPER_RIGHT = { x = 3, y = 2 } | |
35 | ACTIVATOR_UPPER_LEFT = { x = 0, y = 2 } | |
36 | ||
37 | ANALYSER_MAIN = { x = 2, y = -1 } | |
38 | CHEST = { x = 1, y = -1 } | |
39 | TRASH = { x = 3, y = -1 } | |
40 | ||
41 | LOWER_RIGHT = { | |
42 | crop = CROP_LOWER_RIGHT, | |
43 | analyser = ANALYSER_LOWER_RIGHT, | |
44 | analyserFace = ANALYSER_LOWER_FACE, | |
45 | activator = ACTIVATOR_LOWER_RIGHT | |
46 | } | |
47 | ||
48 | LOWER_LEFT = { | |
49 | crop = CROP_LOWER_LEFT, | |
50 | analyser = ANALYSER_LOWER_LEFT, | |
51 | analyserFace = ANALYSER_LOWER_FACE, | |
52 | activator = ACTIVATOR_LOWER_LEFT | |
53 | } | |
54 | ||
55 | UPPER_RIGHT = { | |
56 | crop = CROP_UPPER_RIGHT, | |
57 | analyser = ANALYSER_UPPER_RIGHT, | |
58 | analyserFace = ANALYSER_UPPER_FACE, | |
59 | activator = ACTIVATOR_UPPER_RIGHT | |
60 | } | |
61 | ||
62 | UPPER_LEFT = { | |
63 | crop = CROP_UPPER_LEFT, | |
64 | analyser = ANALYSER_UPPER_LEFT, | |
65 | analyserFace = ANALYSER_UPPER_FACE, | |
66 | activator = ACTIVATOR_UPPER_LEFT | |
67 | } | |
68 | ||
69 | POS_Y = 1 | |
70 | POS_X = 2 | |
71 | NEG_Y = 3 | |
72 | NEG_X = 4 | |
73 | ||
74 | currentFace = POS_Y | |
75 | currentPos = { x = 1, y = -1 } -- same as the chest | |
76 | currentState = STATE_NORMAL | |
77 | ||
78 | STATES = { | |
79 | normal = { LOWER_RIGHT, UPPER_LEFT }, | |
80 | alternate = { LOWER_LEFT, UPPER_RIGHT } | |
81 | } | |
82 | ||
83 | -- | |
84 | -- State management | |
85 | -- | |
86 | function flipCurrentState() | |
87 | if currentState == STATE_NORMAL then | |
88 | currentState = STATE_ALTERNATE | |
89 | else | |
90 | currentState = STATE_NORMAL | |
91 | end | |
92 | end | |
93 | ||
94 | function currentField1() | |
95 | return STATES[currentState][1] | |
96 | end | |
97 | ||
98 | function currentField2() | |
99 | return STATES[currentState][2] | |
100 | end | |
101 | ||
102 | function oppositeState() | |
103 | return currentState == STATE_NORMAL and STATE_ALTERNATE or STATE_NORMAL | |
104 | end | |
105 | ||
106 | function oppositeField1() | |
107 | return STATES[oppositeState()][1] | |
108 | end | |
109 | ||
110 | function oppositeField2() | |
111 | return STATES[oppositeState()][2] | |
112 | end | |
113 | ||
114 | -- | |
115 | -- Movement and orientation | |
116 | -- | |
117 | function turnLeft() | |
118 | turtle.turnLeft() | |
119 | currentFace = currentFace - 1 | |
120 | if currentFace < POS_Y then | |
121 | currentFace = NEG_X | |
122 | end | |
123 | end | |
124 | ||
125 | function turnRight() | |
126 | turtle.turnRight() | |
127 | currentFace = currentFace + 1 | |
128 | if currentFace > NEG_X then | |
129 | currentFace = POS_Y | |
130 | end | |
131 | end | |
132 | ||
133 | function turnToFace(face) | |
134 | local diff = currentFace - face | |
135 | if diff == 0 then | |
136 | return | |
137 | end | |
138 | ||
139 | if math.abs(diff) == 2 then | |
140 | turnLeft() | |
141 | turnLeft() | |
142 | elseif diff == 1 or diff == -3 then | |
143 | turnLeft() | |
144 | elseif diff == -1 or diff == 3 then | |
145 | turnRight() | |
146 | else | |
147 | error("Invalid difference: " + diff) | |
148 | end | |
149 | end | |
150 | ||
151 | function moveForward(times) | |
152 | while times > 0 do | |
153 | turtle.forward() | |
154 | adjustCurrentPos() | |
155 | times = times - 1 | |
156 | end | |
157 | end | |
158 | ||
159 | function adjustCurrentPos() | |
160 | if currentFace == POS_Y then | |
161 | currentPos.y = currentPos.y + 1 | |
162 | elseif currentFace == POS_X then | |
163 | currentPos.x = currentPos.x + 1 | |
164 | elseif currentFace == NEG_Y then | |
165 | currentPos.y = currentPos.y - 1 | |
166 | elseif currentFace == NEG_X then | |
167 | currentPos.x = currentPos.x - 1 | |
168 | else | |
169 | error("Invald face: " + currentFace) | |
170 | end | |
171 | end | |
172 | ||
173 | function moveTo(pos) | |
174 | local diffx = currentPos.x - pos.x | |
175 | local diffy = currentPos.y - pos.y | |
176 | local facex = diffx > 0 and NEG_X or POS_X | |
177 | local facey = diffy > 0 and NEG_Y or POS_Y | |
178 | local absx = math.abs(diffx) | |
179 | local absy = math.abs(diffy) | |
180 | ||
181 | if currentFace == facex then | |
182 | moveForward(absx) | |
183 | if absy > 0 then | |
184 | turnToFace(facey) | |
185 | moveForward(absy) | |
186 | end | |
187 | elseif currentFace == facey then | |
188 | moveForward(absy) | |
189 | if absx > 0 then | |
190 | turnToFace(facex) | |
191 | moveForward(absx) | |
192 | end | |
193 | else | |
194 | if absx > 0 then | |
195 | turnToFace(facex) | |
196 | moveForward(absx) | |
197 | end | |
198 | if absy > 0 then | |
199 | turnToFace(facey) | |
200 | moveForward(absy) | |
201 | end | |
202 | end | |
203 | end | |
204 | ||
205 | -- | |
206 | -- Planting | |
207 | -- | |
208 | ||
209 | function placeCropAndSeed(field) | |
210 | moveTo(field.crop) | |
211 | placeSingleCrop() | |
212 | moveTo(field.activator) | |
213 | placeSeed() | |
214 | end | |
215 | ||
216 | function placeCropAndCrossCrop(field) | |
217 | moveTo(field.crop) | |
218 | placeSingleCrop() | |
219 | moveTo(field.activator) | |
220 | placeCrossCrop() | |
221 | end | |
222 | ||
223 | function placeSingleCrop() | |
224 | turtle.select(SLOT_CROPS) | |
225 | turtle.placeDown() | |
226 | end | |
227 | ||
228 | function placeViaActivator(slot) | |
229 | turtle.select(slot) | |
230 | turtle.dropDown(1) | |
231 | ||
232 | rs.setOutput("bottom", true) | |
233 | os.sleep(ACTIVATOR_PULSE_DURATION) | |
234 | rs.setOutput("bottom", false) | |
235 | end | |
236 | ||
237 | function placeCrossCrop() | |
238 | placeViaActivator(SLOT_CROPS) | |
239 | end | |
240 | ||
241 | function placeSeed() | |
242 | placeViaActivator(SLOT_SEEDS) | |
243 | end | |
244 | ||
245 | function placeAnalyser() | |
246 | turtle.select(SLOT_ANALYSER) | |
247 | sleep(1) | |
248 | turtle.placeDown() | |
249 | sleep(1) | |
250 | ||
251 | return peripheral.wrap("bottom") | |
252 | end | |
253 | ||
254 | function waitForPlantToMature(face) | |
255 | analyser = placeAnalyser() | |
256 | while not analyser.isMature(face) do | |
257 | sleep(MATURE_SLEEP_DURATION) | |
258 | end | |
259 | ||
260 | turtle.digDown() | |
261 | end | |
262 | ||
263 | function waitForPlantToSpread(face) | |
264 | analyser = placeAnalyser() | |
265 | while not analyser.hasPlant(face) do | |
266 | sleep(SPREAD_SLEEP_DURATION) | |
267 | end | |
268 | ||
269 | turtle.digDown() | |
270 | end | |
271 | ||
272 | function waitForMaturePlant(field) | |
273 | moveTo(field.analyser) | |
274 | waitForPlantToMature(field.analyserFace) | |
275 | end | |
276 | ||
277 | function waitForSpread(field) | |
278 | moveTo(field.analyser) | |
279 | waitForPlantToSpread(field.analyserFace) | |
280 | end | |
281 | ||
282 | function harvest(field) | |
283 | moveTo(field.crop) | |
284 | turtle.select(SLOT_CROPS) | |
285 | turtle.digDown() | |
286 | end | |
287 | ||
288 | -- true if item at slot i should get dumped | |
289 | -- returns true for everything that doesnt contain the word "seed" in the technical name | |
290 | function dumpItem(i) | |
291 | local item = turtle.getItemDetail(i) | |
292 | if item == nil then | |
293 | return false | |
294 | end | |
295 | ||
296 | return string.find(string.lower(item.name), "seed") == nil | |
297 | end | |
298 | ||
299 | -- dumps all items that are not seeds into chest below, also returns slot numbers for the 2 collected seeds | |
300 | function dumpHarvest() | |
301 | moveTo(CHEST) | |
302 | ||
303 | local s1 = nil | |
304 | local s2 = nil | |
305 | ||
306 | for i=3,16 do | |
307 | if dumpItem(i) then | |
308 | turtle.select(i) | |
309 | turtle.dropDown() | |
310 | elseif turtle.getItemDetail(i) ~= nil then | |
311 | if s1 == nil then | |
312 | s1 = i | |
313 | else | |
314 | s2 = i | |
315 | end | |
316 | end | |
317 | end | |
318 | return s1, s2 | |
319 | end | |
320 | ||
321 | function analyseSlotGetStats(slot) | |
322 | analyser = placeAnalyser() | |
323 | turtle.select(slot) | |
324 | turtle.dropDown() | |
325 | analyser.analyze() | |
326 | ||
327 | while not analyser.isAnalyzed() do | |
328 | sleep(ANALYSER_SLEEP_DURATION) | |
329 | end | |
330 | ||
331 | gr, ga, str = analyser.getSpecimenStats() | |
332 | ||
333 | turtle.suckDown() | |
334 | turtle.select(SLOT_ANALYSER) | |
335 | turtle.digDown() | |
336 | ||
337 | return ((gr + ga + str) == 30) | |
338 | end | |
339 | ||
340 | ||
341 | function analyseSlotAndStore(slot) | |
342 | if slot == nil then | |
343 | return false | |
344 | end | |
345 | ||
346 | moveTo(ANALYSER_MAIN) | |
347 | local has30 = analyseSlotGetStats(slot) | |
348 | ||
349 | if has30 then | |
350 | moveTo(CHEST) | |
351 | else | |
352 | moveTo(TRASH) | |
353 | end | |
354 | ||
355 | turtle.select(slot) | |
356 | turtle.dropDown() | |
357 | return has30 | |
358 | end | |
359 | ||
360 | function analyseHarvest(s1, s2) | |
361 | local s1Has30 = analyseSlotAndStore(s1) | |
362 | local s2Has30 = analyseSlotAndStore(s2) | |
363 | ||
364 | return s1Has30 or s2Has30 | |
365 | end | |
366 | ||
367 | function main() | |
368 | placeCropAndSeed(currentField1()) | |
369 | placeCropAndSeed(currentField2()) | |
370 | ||
371 | local finishedBreeding = false | |
372 | ||
373 | while not finishedBreeding do | |
374 | waitForMaturePlant(currentField1()) | |
375 | waitForMaturePlant(currentField2()) | |
376 | ||
377 | placeCropAndCrossCrop(oppositeField1()) | |
378 | placeCropAndCrossCrop(oppositeField2()) | |
379 | ||
380 | waitForSpread(oppositeField1()) | |
381 | waitForSpread(oppositeField2()) | |
382 | ||
383 | harvest(currentField1()) | |
384 | harvest(currentField2()) | |
385 | ||
386 | s1, s2 = dumpHarvest() | |
387 | finishedBreeding = analyseHarvest(s1, s2) | |
388 | ||
389 | flipCurrentState() | |
390 | end | |
391 | ||
392 | -- harvest remaining 2 and store them | |
393 | harvest(currentField1()) | |
394 | harvest(currentField2()) | |
395 | s1, s2 = dumpHarvest() | |
396 | analyseHarvest(s1, s2) | |
397 | ||
398 | -- reset position | |
399 | moveTo(CHEST) | |
400 | turnToFace(POS_Y) | |
401 | end | |
402 | ||
403 | main() |