// No direct THREE.js import needed /** * Daily Routine System for Villager AI * * This implementation manages villager daily routines including work, rest, and social interactions. * It uses a schedule-based approach with some randomness to create natural-looking behavior. */ class DailyRoutineManager { constructor() { this.schedules = new Map(); // Map of villager IDs to schedules this.currentTime = 0; // In-game time in hours (0-24) } /** * Set a schedule for a villager * @param {string} villagerId - Villager identifier * @param {Array} schedule - Array of schedule entries */ setSchedule(villagerId, schedule) { this.schedules.set(villagerId, schedule); } /** * Update the routine manager * @param {number} deltaTime - Time since last update in hours */ update(deltaTime) { this.currentTime += deltaTime; if (this.currentTime >= 24) { this.currentTime -= 24; // Wrap around to next day } } /** * Get current activity for a villager * @param {string} villagerId - Villager identifier * @returns {Object} Current activity */ getCurrentActivity(villagerId) { const schedule = this.schedules.get(villagerId); if (!schedule) return null; // Find the current activity based on time for (let i = schedule.length - 1; i >= 0; i--) { if (this.currentTime >= schedule[i].startTime) { return schedule[i]; } } // If no activity found, return the last one (for times before first activity) return schedule[schedule.length - 1]; } /** * Create a default schedule for a villager * @param {string} villagerId - Villager identifier * @param {Object} workLocation - Work location * @param {Object} homeLocation - Home location * @param {Array} socialLocations - Social locations */ createDefaultSchedule(villagerId, workLocation, homeLocation, socialLocations) { const schedule = [ { startTime: 0, activity: 'sleep', location: homeLocation }, { startTime: 7, activity: 'eat', location: homeLocation }, { startTime: 8, activity: 'work', location: workLocation }, { startTime: 12, activity: 'eat', location: workLocation }, { startTime: 13, activity: 'work', location: workLocation }, { startTime: 17, activity: 'socialize', location: socialLocations[0] }, { startTime: 19, activity: 'eat', location: homeLocation }, { startTime: 20, activity: 'sleep', location: homeLocation } ]; this.setSchedule(villagerId, schedule); } } /** * Villager class with routine-based behavior */ class Villager { constructor(id, position) { this.id = id; this.position = position; this.velocity = [0, 0, 0]; // Simple array instead of THREE.Vector3 this.maxSpeed = 2; this.energy = 100; this.hunger = 0; this.socialNeed = 0; this.state = 'idle'; // idle, working, sleeping, eating, socializing this.path = []; this.avoidanceRadius = 2; this.avoidanceWeight = 1.5; this.steeringWeight = 1.0; } /** * Calculate distance between two points * @param {Array} pos1 - First position [x, y, z] * @param {Array} pos2 - Second position [x, y, z] * @returns {number} Distance between points */ calculateDistance(pos1, pos2) { return Math.sqrt( Math.pow(pos1[0] - pos2[0], 2) + Math.pow(pos1[1] - pos2[1], 2) + Math.pow(pos1[2] - pos2[2], 2) ); } /** * Update villager state * @param {DailyRoutineManager} routineManager - Routine manager * @param {VillagePathfinder} pathfinder - Pathfinding system * @param {number} deltaTime - Time since last update */ update(routineManager, pathfinder, deltaTime) { // Update needs this.updateNeeds(deltaTime); // Get current activity const activity = routineManager.getCurrentActivity(this.id); // Update state based on activity if (activity) { this.state = activity.activity; // If we have a location for this activity, pathfind to it if (activity.location && this.calculateDistance(this.position, activity.location) > 1) { this.path = pathfinder.findPath(this.position, activity.location); } else { this.path = []; } } // Perform state-specific actions switch (this.state) { case 'sleep': this.sleep(deltaTime); break; case 'work': this.work(deltaTime); break; case 'eat': this.eat(deltaTime); break; case 'socialize': this.socialize(deltaTime); break; } } /** * Update villager needs over time * @param {number} deltaTime - Time since last update */ updateNeeds(deltaTime) { this.energy = Math.max(0, this.energy - 0.1 * deltaTime); this.hunger = Math.min(100, this.hunger + 0.05 * deltaTime); this.socialNeed = Math.min(100, this.socialNeed + 0.03 * deltaTime); } /** * Check if villager is tired * @returns {boolean} True if tired */ isTired() { return this.energy < 20; } /** * Check if villager should work * @returns {boolean} True if should work */ shouldWork() { return this.energy > 30 && this.hunger < 80; } /** * Check if villager should socialize * @returns {boolean} True if should socialize */ shouldSocialize() { return this.energy > 40 && this.socialNeed > 50; } /** * Sleep action * @param {number} deltaTime - Time since last update */ sleep(deltaTime) { this.energy = Math.min(100, this.energy + 0.5 * deltaTime); } /** * Work action * @param {number} deltaTime - Time since last update */ work(deltaTime) { this.energy = Math.max(0, this.energy - 0.2 * deltaTime); } /** * Eat action * @param {number} deltaTime - Time since last update */ eat(deltaTime) { this.hunger = Math.max(0, this.hunger - 0.8 * deltaTime); } /** * Socialize action * @param {number} deltaTime - Time since last update */ socialize(deltaTime) { this.socialNeed = Math.max(0, this.socialNeed - 0.6 * deltaTime); } /** * Idle action */ idle() { // Do nothing } } export { DailyRoutineManager, Villager };