131 lines
4.5 KiB
JavaScript
131 lines
4.5 KiB
JavaScript
// states/Idle.js
|
|
const { getBot, getActiveTask, isCombatLocked, getStateMachine } = require('../core/context');
|
|
const context = require('../core/context');
|
|
const { chatWithAI } = require('../lib/ai-helper');
|
|
const config = require('../config.json');
|
|
const { GoalNear } = require('mineflayer-pathfinder').goals;
|
|
const { getHomeZone } = require('../memory/locations');
|
|
const db = require('../db');
|
|
|
|
module.exports = async function Idle() {
|
|
const bot = getBot();
|
|
|
|
if (getActiveTask() || isCombatLocked()) {
|
|
console.log('[IDLE] Skipping — locked by task or combat.');
|
|
return;
|
|
}
|
|
|
|
console.log('[STATE] Idle');
|
|
|
|
return new Promise(resolve => {
|
|
|
|
// Follow and observe a player that is close by. This should eventually become a method to help the player.
|
|
const players = Object.values(bot.players).filter(p => p.username !== bot.username && p.entity);
|
|
if (players.length > 0) {
|
|
const target = players[0].entity;
|
|
const distance = bot.entity.position.distanceTo(target.position);
|
|
|
|
if (distance > 5 || distance < 2) {
|
|
bot.chat(`Following ${players[0].username}...`);
|
|
bot.pathfinder.setGoal(new GoalNear(target.position.x, target.position.y, target.position.z, 2));
|
|
}
|
|
|
|
setTimeout(() => {
|
|
getStateMachine().transition('Observe');
|
|
resolve();
|
|
}, 10000);
|
|
return;
|
|
}
|
|
|
|
getHomeZone(db, async (err, zone) => {
|
|
const fallbackCenter = { x: 100, y: 64, z: 100 };
|
|
const fallbackBounds = { x: 20, y: 10, z: 20 };
|
|
|
|
const center = zone?.center || fallbackCenter;
|
|
const bounds = zone?.bounds || fallbackBounds;
|
|
const safeRadius = Math.min(bounds.x, bounds.z);
|
|
|
|
const prompt = `You're in a safe zone. What would be a useful task to do right now? Your options are: cut grass, tend crops, patrol for mobs.`;
|
|
const response = await chatWithAI(prompt, config.ai);
|
|
|
|
|
|
// Randomize an action to do things around the home area.
|
|
if (response.includes('grass')) {
|
|
const grass = bot.findBlock({
|
|
matching: block => block.name === 'tall_grass',
|
|
maxDistance: safeRadius
|
|
});
|
|
|
|
// Cut grass
|
|
if (grass) {
|
|
await bot.pathfinder.setGoal(new GoalNear(grass.position.x, grass.position.y, grass.position.z, 1));
|
|
try {
|
|
await bot.dig(grass);
|
|
bot.chat("Trimming grass.");
|
|
} catch {}
|
|
}
|
|
|
|
// manage a farm by harvesting crops.
|
|
} else if (response.includes('crop') || response.includes('farm')) {
|
|
const crops = bot.findBlocks({
|
|
matching: block => ['wheat', 'carrots', 'potatoes'].includes(block.name),
|
|
maxDistance: safeRadius,
|
|
count: 5
|
|
});
|
|
|
|
for (const pos of crops) {
|
|
const crop = bot.blockAt(pos);
|
|
if (crop.metadata === 7) {
|
|
await bot.pathfinder.setGoal(new GoalNear(pos.x, pos.y, pos.z, 1));
|
|
try {
|
|
await bot.dig(crop);
|
|
bot.chat("Harvesting a crop.");
|
|
// TODO: Replanting logic needs to be added here. This might be a state or a task.. not sure yet.
|
|
} catch {}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Find and attack mobs.
|
|
} else if (response.includes('mob') || response.includes('patrol')) {
|
|
|
|
const mob = Object.values(bot.entities).find(e =>
|
|
e.type === 'mob' &&
|
|
e.position.distanceTo(bot.entity.position) <= safeRadius &&
|
|
e.username !== bot.username
|
|
);
|
|
|
|
if (mob) {
|
|
context.setCombatLock(true);
|
|
bot.chat(`Engaging ${mob.name}.`);
|
|
bot.attack(mob);
|
|
|
|
bot.once('death', () => {
|
|
context.setCombatLock(false);
|
|
bot.chat("I died. Lock released.");
|
|
});
|
|
|
|
// Monitor mobs and release combat lock when clear
|
|
const checkClear = setInterval(() => {
|
|
const nearbyMobs = Object.values(bot.entities).filter(e => e.type === 'mob');
|
|
if (nearbyMobs.length === 0) {
|
|
context.setCombatLock(false);
|
|
clearInterval(checkClear);
|
|
bot.chat("Area is clear.");
|
|
}
|
|
}, 3000);
|
|
} else {
|
|
const dx = Math.floor(Math.random() * safeRadius * 2 - safeRadius);
|
|
const dz = Math.floor(Math.random() * safeRadius * 2 - safeRadius);
|
|
const pos = bot.entity.position.offset(dx, 0, dz);
|
|
bot.pathfinder.setGoal(new GoalNear(pos.x, pos.y, pos.z, 1));
|
|
}
|
|
}
|
|
|
|
setTimeout(() => {
|
|
getStateMachine().transition('Observe');
|
|
resolve();
|
|
}, 10000 );
|
|
});
|
|
});
|
|
};
|