/** * NPC SETTLEMENT SYSTEM (Magic Helpers) * NPCs auto-assist with tasks * Worker efficiency, happiness, housing */ export class NPCSettlementSystem { constructor(scene) { this.scene = scene; // Settled NPCs this.settledNPCs = new Map(); // Worker assignments this.assignments = new Map(); // npcId → task // NPC stats this.npcHappiness = new Map(); // npcId → happiness (0-100) this.npcEfficiency = new Map(); // npcId → efficiency (0.5-2.0) // Housing this.npcHomes = new Map(); // npcId → buildingId this.housingCapacity = 0; // Task types this.taskTypes = ['farming', 'building', 'crafting', 'defense', 'gathering']; this.init(); } init() { // Update worker tasks periodically this.scene.time.addEvent({ delay: 5000, // Every 5s callback: () => this.updateWorkers(), loop: true }); // Update happiness hourly this.scene.time.addEvent({ delay: 3600000, // 1 hour callback: () => this.updateHappiness(), loop: true }); } /** * Settle an NPC (they join the town) */ settleNPC(npcId, npcData) { if (this.settledNPCs.has(npcId)) return false; //Check housing availability if (this.settledNPCs.size >= this.housingCapacity) { console.warn('No housing available'); return false; } this.settledNPCs.set(npcId, { id: npcId, name: npcData.name, skills: npcData.skills || [], assignedTask: null, ...npcData }); // Initial stats this.npcHappiness.set(npcId, 75); // Start at 75% happiness this.npcEfficiency.set(npcId, 1.0); // Base efficiency // Notification this.scene.uiSystem?.showNotification( `${npcData.name} has joined the settlement!`, 'success', { icon: 'npc_join' } ); console.log(`🏘️ ${npcData.name} settled in town`); return true; } /** * Assign NPC to task */ assignTask(npcId, taskType, taskData) { const npc = this.settledNPCs.get(npcId); if (!npc) return false; // Check if NPC has skill for task if (!npc.skills.includes(taskType)) { console.warn(`${npc.name} lacks skill: ${taskType}`); return false; } // Assign npc.assignedTask = taskType; this.assignments.set(npcId, { type: taskType, data: taskData, startTime: Date.now() }); console.log(`👷 ${npc.name} assigned to ${taskType}`); return true; } /** * Unassign NPC from task */ unassignTask(npcId) { const npc = this.settledNPCs.get(npcId); if (!npc) return false; npc.assignedTask = null; this.assignments.delete(npcId); console.log(`${npc.name} unassigned`); return true; } /** * Update all worker tasks */ updateWorkers() { this.assignments.forEach((assignment, npcId) => { const npc = this.settledNPCs.get(npcId); const efficiency = this.npcEfficiency.get(npcId) || 1.0; switch (assignment.type) { case 'farming': this.performFarming(npc, efficiency, assignment.data); break; case 'building': this.performBuilding(npc, efficiency, assignment.data); break; case 'crafting': this.performCrafting(npc, efficiency, assignment.data); break; case 'defense': this.performDefense(npc, efficiency); break; case 'gathering': this.performGathering(npc, efficiency); break; } }); } /** * WORKER TASKS */ performFarming(npc, efficiency, data) { // Auto-tend crops const crops = this.scene.crops || []; const tendsPerCycle = Math.floor(2 * efficiency); for (let i = 0; i < tendsPerCycle && i < crops.length; i++) { const crop = crops[i]; crop.water?.(); crop.fertilize?.(); } // Chance to auto-harvest if (Math.random() < 0.1 * efficiency) { const harvestable = crops.find(c => c.isHarvestable); if (harvestable) { this.scene.farmingSystem?.harvestCrop(harvestable); console.log(`${npc.name} harvested crop`); } } } performBuilding(npc, efficiency, data) { // Speed up construction const building = data.buildingId ? this.scene.buildingSystem?.getBuilding(data.buildingId) : null; if (building && building.isUnderConstruction) { const progressBonus = 5 * efficiency; building.constructionProgress += progressBonus; if (building.constructionProgress >= 100) { this.scene.buildingSystem?.completeConstruction(building.id); console.log(`${npc.name} completed building: ${building.name}`); } } } performCrafting(npc, efficiency, data) { // Auto-craft items if (data.recipe) { const canCraft = this.scene.craftingSystem?.canCraft(data.recipe); if (canCraft && Math.random() < 0.2 * efficiency) { this.scene.craftingSystem?.craft(data.recipe); console.log(`${npc.name} crafted ${data.recipe}`); } } } performDefense(npc, efficiency) { // Patrol and defend // Increased detection range for raids this.scene.gameState.buffs.raid_detection_range = (this.scene.gameState.buffs.raid_detection_range || 1.0) + (0.1 * efficiency); // Auto-repair walls/defenses const defenses = this.scene.defenseSystem?.getAllDefenses() || []; defenses.forEach(defense => { if (defense.health < defense.maxHealth && Math.random() < 0.05 * efficiency) { defense.health = Math.min(defense.maxHealth, defense.health + 10); console.log(`${npc.name} repaired ${defense.name}`); } }); } performGathering(npc, efficiency) { // Auto-gather resources const gatherChance = 0.15 * efficiency; if (Math.random() < gatherChance) { const resources = ['wood', 'stone', 'berries', 'herbs']; const resource = Phaser.Utils.Array.GetRandom(resources); const amount = Math.floor(Phaser.Math.Between(1, 3) * efficiency); this.scene.inventorySystem?.addItem(resource, amount); console.log(`${npc.name} gathered ${amount} ${resource}`); } } /** * Update NPC happiness */ updateHappiness() { this.settledNPCs.forEach((npc, npcId) => { let happiness = this.npcHappiness.get(npcId) || 50; // Factors affecting happiness const hasHome = this.npcHomes.has(npcId); const hasTask = npc.assignedTask !== null; const isOverworked = hasTask && this.assignments.get(npcId)?.overworked; // Adjustments if (hasHome) happiness += 5; if (hasTask) happiness += 2; if (isOverworked) happiness -= 10; if (!hasHome && this.settledNPCs.size > this.housingCapacity) happiness -= 15; // Natural decay happiness -= 1; // Clamp happiness = Math.max(0, Math.min(100, happiness)); this.npcHappiness.set(npcId, happiness); // Update efficiency based on happiness const efficiency = 0.5 + (happiness / 100) * 1.5; // 0.5-2.0 this.npcEfficiency.set(npcId, efficiency); // Low happiness warning if (happiness < 30) { this.scene.uiSystem?.showNotification( `${npc.name} is unhappy!`, 'warning' ); console.warn(`${npc.name} happiness: ${happiness}`); } }); } /** * Assign NPC to home */ assignHome(npcId, buildingId) { this.npcHomes.set(npcId, buildingId); // Happiness boost const happiness = this.npcHappiness.get(npcId) || 50; this.npcHappiness.set(npcId, Math.min(100, happiness + 20)); console.log(`${this.settledNPCs.get(npcId).name} moved into home`); } /** * Increase housing capacity */ addHousing(capacity) { this.housingCapacity += capacity; console.log(`Housing capacity: ${this.housingCapacity}`); } /** * Get settlement statistics */ getSettlementStats() { const npcs = Array.from(this.settledNPCs.values()); const avgHappiness = npcs.reduce((sum, npc) => sum + (this.npcHappiness.get(npc.id) || 0), 0) / npcs.length || 0; const avgEfficiency = npcs.reduce((sum, npc) => sum + (this.npcEfficiency.get(npc.id) || 1), 0) / npcs.length || 1; return { population: npcs.length, housingCapacity: this.housingCapacity, averageHappiness: Math.round(avgHappiness), averageEfficiency: avgEfficiency.toFixed(2), assignedWorkers: this.assignments.size, unemployed: npcs.length - this.assignments.size }; } /** * Get NPCs by skill */ getNPCsBySkill(skill) { return Array.from(this.settledNPCs.values()).filter(npc => npc.skills.includes(skill)); } /** * Save/Load */ getSaveData() { return { settledNPCs: Array.from(this.settledNPCs.entries()), assignments: Array.from(this.assignments.entries()), npcHappiness: Array.from(this.npcHappiness.entries()), npcHomes: Array.from(this.npcHomes.entries()), housingCapacity: this.housingCapacity }; } loadSaveData(data) { this.settledNPCs = new Map(data.settledNPCs || []); this.assignments = new Map(data.assignments || []); this.npcHappiness = new Map(data.npcHappiness || []); this.npcHomes = new Map(data.npcHomes || []); this.housingCapacity = data.housingCapacity || 0; // Recalculate efficiency this.npcHappiness.forEach((happiness, npcId) => { const efficiency = 0.5 + (happiness / 100) * 1.5; this.npcEfficiency.set(npcId, efficiency); }); } }