import { PRODUCTIVITY_RECOVERY_RATE, PRODUCTIVITY_THRESHOLD, type Needs, type Movement, type NPCBrain, type Position, } from '@dflike/shared'; import type { World } from '../ecs/World.js'; import type { GameMap } from '../map/GameMap.js'; import { getEffectiveStat } from './statHelpers.js'; import { addItem } from '../industry/inventoryHelpers.js'; import { industryConfig } from '../config/industryConfig.js'; export interface GatheringState { resourceType: string; ticksRemaining: number; } export function gatheringSystem(world: World, map: GameMap): void { for (const entity of world.query('npcBrain', 'position', 'needs', 'movement')) { const brain = world.getComponent(entity, 'npcBrain')!; if (brain.currentGoal !== 'gather') continue; const pos = world.getComponent(entity, 'position')!; const needs = world.getComponent(entity, 'needs')!; const movement = world.getComponent(entity, 'movement')!; const gs = world.getComponent(entity, 'gatheringState'); // Already gathering — tick down if (gs) { gs.ticksRemaining--; needs.productivity = Math.min(100, needs.productivity + PRODUCTIVITY_RECOVERY_RATE); if (gs.ticksRemaining <= 0) { // Complete: add resource to inventory const inv = world.getComponent>(entity, 'inventory'); if (inv) { addItem(inv, gs.resourceType, industryConfig.gatherYield); } world.removeComponent(entity, 'gatheringState'); // Decide next action if (needs.productivity >= PRODUCTIVITY_THRESHOLD) { brain.currentGoal = 'wander'; } // else brain stays on 'gather', npcBrain will pick new target next tick } continue; } // Not yet gathering — check if at resource tile and idle if (movement.state !== 'idle') continue; const resourceTile = map.resourceTiles.find(r => r.x === pos.x && r.y === pos.y); if (!resourceTile) continue; // Start gathering const str = getEffectiveStat(world, entity, 'strength'); const baseTicks = industryConfig.gatherBaseTicks; const ticks = Math.max(1, Math.round(baseTicks * (1 - (str - 10) * industryConfig.gatherStrengthModifier))); world.addComponent(entity, 'gatheringState', { resourceType: resourceTile.resourceType, ticksRemaining: ticks, }); // Recover productivity on first tick too needs.productivity = Math.min(100, needs.productivity + PRODUCTIVITY_RECOVERY_RATE); } }