feat(systems): add gatheringSystem with timer, stat modifier, and inventory
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
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<NPCBrain>(entity, 'npcBrain')!;
|
||||
|
||||
if (brain.currentGoal !== 'gather') continue;
|
||||
|
||||
const pos = world.getComponent<Position>(entity, 'position')!;
|
||||
const needs = world.getComponent<Needs>(entity, 'needs')!;
|
||||
const movement = world.getComponent<Movement>(entity, 'movement')!;
|
||||
const gs = world.getComponent<GatheringState>(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<Map<string, number>>(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<GatheringState>(entity, 'gatheringState', {
|
||||
resourceType: resourceTile.resourceType,
|
||||
ticksRemaining: ticks,
|
||||
});
|
||||
|
||||
// Recover productivity on first tick too
|
||||
needs.productivity = Math.min(100, needs.productivity + PRODUCTIVITY_RECOVERY_RATE);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user