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 |
5 | + | ACTIVATOR_PULSE_DURATION = 0.92 |
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 | turtle.placeDown() | |
248 | os.sleep(ANALYSE_SLEEP_DURATION) | |
249 | ||
250 | return peripheral.wrap("bottom") | |
251 | end | |
252 | ||
253 | function waitForPlantToMature(face) | |
254 | analyser = placeAnalyser() | |
255 | while not analyser.isMature(face) do | |
256 | sleep(MATURE_SLEEP_DURATION) | |
257 | end | |
258 | ||
259 | turtle.digDown() | |
260 | end | |
261 | ||
262 | function waitForPlantToSpread(face) | |
263 | analyser = placeAnalyser() | |
264 | while not analyser.hasPlant(face) do | |
265 | sleep(SPREAD_SLEEP_DURATION) | |
266 | end | |
267 | ||
268 | turtle.digDown() | |
269 | end | |
270 | ||
271 | function waitForMaturePlant(field) | |
272 | moveTo(field.analyser) | |
273 | waitForPlantToMature(field.analyserFace) | |
274 | end | |
275 | ||
276 | function waitForSpread(field) | |
277 | moveTo(field.analyser) | |
278 | waitForPlantToSpread(field.analyserFace) | |
279 | end | |
280 | ||
281 | function harvest(field) | |
282 | moveTo(field.crop) | |
283 | turtle.select(SLOT_CROPS) | |
284 | turtle.digDown() | |
285 | end | |
286 | ||
287 | -- true if item at slot i should get dumped | |
288 | -- returns true for everything that doesnt contain the word "seed" in the technical name | |
289 | function dumpItem(i) | |
290 | local item = turtle.getItemDetail(i) | |
291 | if item == nil then | |
292 | return false | |
293 | end | |
294 | ||
295 | return string.find(string.lower(item.name), "seed") == nil | |
296 | end | |
297 | ||
298 | -- dumps all items that are not seeds into chest below, also returns slot numbers for the 2 collected seeds | |
299 | function dumpHarvest() | |
300 | moveTo(CHEST) | |
301 | ||
302 | local s1 = nil | |
303 | local s2 = nil | |
304 | ||
305 | for i=3,16 do | |
306 | if dumpItem(i) then | |
307 | turtle.select(i) | |
308 | turtle.dropDown() | |
309 | elseif turtle.getItemDetail(i) ~= nil then | |
310 | if s1 == nil then | |
311 | s1 = i | |
312 | else | |
313 | s2 = i | |
314 | end | |
315 | end | |
316 | end | |
317 | return s1, s2 | |
318 | end | |
319 | ||
320 | function analyseSlotGetStats(slot) | |
321 | analyser = placeAnalyser() | |
322 | turtle.select(slot) | |
323 | turtle.dropDown() | |
324 | analyser.analyze() | |
325 | ||
326 | while not analyser.isAnalyzed() do | |
327 | sleep(ANALYSER_SLEEP_DURATION) | |
328 | end | |
329 | ||
330 | gr, ga, str = analyser.getSpecimenStats() | |
331 | ||
332 | turtle.suckDown() | |
333 | turtle.select(SLOT_ANALYSER) | |
334 | turtle.digDown() | |
335 | ||
336 | return ((gr + ga + str) == 30) | |
337 | end | |
338 | ||
339 | ||
340 | function analyseSlotAndStore(slot) | |
341 | if slot == nil then | |
342 | return false | |
343 | end | |
344 | ||
345 | moveTo(ANALYSER_MAIN) | |
346 | local has30 = analyseSlotGetStats(slot) | |
347 | ||
348 | if has30 then | |
349 | moveTo(CHEST) | |
350 | else | |
351 | moveTo(TRASH) | |
352 | end | |
353 | ||
354 | turtle.select(slot) | |
355 | turtle.dropDown() | |
356 | return has30 | |
357 | end | |
358 | ||
359 | function analyseHarvest(s1, s2) | |
360 | local s1Has30 = analyseSlotAndStore(s1) | |
361 | local s2Has30 = analyseSlotAndStore(s2) | |
362 | ||
363 | return s1Has30 or s2Has30 | |
364 | end | |
365 | ||
366 | function main() | |
367 | placeCropAndSeed(currentField1()) | |
368 | placeCropAndSeed(currentField2()) | |
369 | ||
370 | local finishedBreeding = false | |
371 | ||
372 | while not finishedBreeding do | |
373 | waitForMaturePlant(currentField1()) | |
374 | waitForMaturePlant(currentField2()) | |
375 | ||
376 | placeCropAndCrossCrop(oppositeField1()) | |
377 | placeCropAndCrossCrop(oppositeField2()) | |
378 | ||
379 | waitForSpread(oppositeField1()) | |
380 | waitForSpread(oppositeField2()) | |
381 | ||
382 | harvest(currentField1()) | |
383 | harvest(currentField2()) | |
384 | ||
385 | s1, s2 = dumpHarvest() | |
386 | finishedBreeding = analyseHarvest(s1, s2) | |
387 | ||
388 | flipCurrentState() | |
389 | end | |
390 | ||
391 | -- harvest remaining 2 and store them | |
392 | harvest(currentField1()) | |
393 | harvest(currentField2()) | |
394 | s1, s2 = dumpHarvest() | |
395 | analyseHarvest(s1, s2) | |
396 | ||
397 | -- reset position | |
398 | moveTo(CHEST) | |
399 | turnToFace(POS_Y) | |
400 | end | |
401 | ||
402 | main() |