/** * FarmingState - Automated farming (plant, harvest, replant) * Works with wheat, carrots, potatoes, beetroot, etc. */ import { BaseState } from './BaseState.js'; const CROP_SEEDS = { 'minecraft:wheat': 'minecraft:wheat_seeds', 'minecraft:carrots': 'minecraft:carrot', 'minecraft:potatoes': 'minecraft:potato', 'minecraft:beetroots': 'minecraft:beetroot_seeds', }; export class FarmingState extends BaseState { constructor(turtle, data = {}) { super(turtle, data); this.area = data.area || null; // {minX, minZ, maxX, maxZ, y} this.harvestCount = 0; } get name() { return 'farming'; } get description() { return `Farming - ${this.harvestCount} harvested`; } async *act() { console.log(`[${this.turtle.id}] Starting farming operation`); if (!this.area) { console.log(`[${this.turtle.id}] No farming area defined`); this.turtle.setState('idle'); return; } // Farm in a zigzag pattern over the area const { minX, minZ, maxX, maxZ, y } = this.area; let direction = 1; // 1 = positive Z, -1 = negative Z for (let x = minX; x <= maxX; x++) { const zStart = direction === 1 ? minZ : maxZ; const zEnd = direction === 1 ? maxZ : minZ; const zStep = direction; for (let z = zStart; direction === 1 ? z <= zEnd : z >= zEnd; z += zStep) { if (this.cancelled) return; // Navigate to position above the crop const target = { x, y: y + 1, z }; const navGen = this.navigateTo(target); for await (const _ of navGen) { if (this.cancelled) return; yield; } // Check the block below const blockBelow = await this.exec(` local hasBlock, data = turtle.inspectDown() if hasBlock then return {name = data.name, state = data.state} end return nil `); if (blockBelow) { // Check if crop is mature (age = 7 for most crops) const isMature = blockBelow.state && blockBelow.state.age === 7; if (isMature) { // Harvest await this.exec('turtle.digDown()'); this.harvestCount++; // Replant const seedName = CROP_SEEDS[blockBelow.name]; if (seedName) { await this.exec(` for slot = 1, 16 do local item = turtle.getItemDetail(slot) if item and item.name == "${seedName}" then turtle.select(slot) turtle.placeDown() turtle.select(1) return true end end return false `); } } } yield; } direction *= -1; // Zigzag } // Done farming one pass - check inventory const isFull = await this.isInventoryFull(); if (isFull) { this.turtle.setState('goHome', { reason: 'inventory_full', returnState: 'farming', returnData: this.data }); } else { // Start another pass console.log(`[${this.turtle.id}] Farm pass complete, ${this.harvestCount} harvested`); yield* this.act(); // Loop } } getRecoveryData() { return { ...super.getRecoveryData(), data: { area: this.area, }, }; } }