feat(needs): add productivity decay to needsDecaySystem
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,12 +5,12 @@ import { needsDecaySystem } from '../needsDecaySystem.js';
|
||||
import { npcBrainSystem } from '../npcBrainSystem.js';
|
||||
import { movementSystem } from '../movementSystem.js';
|
||||
import type { Needs, Movement, NPCBrain, Position, SocialState, Stats, StatModifiers } from '@dflike/shared';
|
||||
import { HUNGER_DECAY_PER_TICK, ENERGY_DECAY_PER_TICK, MOVE_SPEED } from '@dflike/shared';
|
||||
import { HUNGER_DECAY_PER_TICK, ENERGY_DECAY_PER_TICK, PRODUCTIVITY_DECAY_PER_TICK, MOVE_SPEED } from '@dflike/shared';
|
||||
|
||||
function createNPC(world: World, x: number, y: number, hunger = 80, energy = 80) {
|
||||
const e = world.createEntity();
|
||||
world.addComponent<Position>(e, 'position', { x, y });
|
||||
world.addComponent<Needs>(e, 'needs', { hunger, energy });
|
||||
world.addComponent<Needs>(e, 'needs', { hunger, energy, productivity: 80 });
|
||||
world.addComponent<Movement>(e, 'movement', { state: 'idle', target: null, path: [], direction: 0, moveProgress: 0 });
|
||||
world.addComponent<NPCBrain>(e, 'npcBrain', { currentGoal: null, goalQueue: [] });
|
||||
return e;
|
||||
@@ -79,6 +79,24 @@ describe('needsDecaySystem', () => {
|
||||
expect(needs.hunger).toBeCloseTo(50 - HUNGER_DECAY_PER_TICK);
|
||||
});
|
||||
|
||||
it('decays productivity each tick', () => {
|
||||
const world = new World();
|
||||
const e = createNPC(world, 0, 0, 50, 50);
|
||||
needsDecaySystem(world);
|
||||
const needs = world.getComponent<Needs>(e, 'needs')!;
|
||||
expect(needs.productivity).toBeCloseTo(80 - PRODUCTIVITY_DECAY_PER_TICK);
|
||||
});
|
||||
|
||||
it('productivity decay is not affected by constitution', () => {
|
||||
const world = new World();
|
||||
const e = createNPC(world, 0, 0, 50, 50);
|
||||
addStats(world, e, { constitution: 18 });
|
||||
needsDecaySystem(world);
|
||||
const needs = world.getComponent<Needs>(e, 'needs')!;
|
||||
// Same decay regardless of constitution
|
||||
expect(needs.productivity).toBeCloseTo(80 - PRODUCTIVITY_DECAY_PER_TICK);
|
||||
});
|
||||
|
||||
it('clamps needs at 0', () => {
|
||||
const world = new World();
|
||||
const e = createNPC(world, 0, 0, 0.01, 0.01);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { HUNGER_DECAY_PER_TICK, ENERGY_DECAY_PER_TICK, HUNGER_THRESHOLD, ENERGY_THRESHOLD, type Needs } from '@dflike/shared';
|
||||
import { HUNGER_DECAY_PER_TICK, ENERGY_DECAY_PER_TICK, PRODUCTIVITY_DECAY_PER_TICK, HUNGER_THRESHOLD, ENERGY_THRESHOLD, PRODUCTIVITY_THRESHOLD, type Needs } from '@dflike/shared';
|
||||
import type { World } from '../ecs/World.js';
|
||||
import { getEffectiveStat } from './statHelpers.js';
|
||||
import type { EventMemoryService } from '../llm/eventMemoryService.js';
|
||||
@@ -10,8 +10,10 @@ export function needsDecaySystem(world: World, eventMemoryService?: EventMemoryS
|
||||
const conMultiplier = 1 - (con - 10) * 0.03;
|
||||
const prevHunger = needs.hunger;
|
||||
const prevEnergy = needs.energy;
|
||||
const prevProductivity = needs.productivity;
|
||||
needs.hunger = Math.max(0, needs.hunger - HUNGER_DECAY_PER_TICK * conMultiplier);
|
||||
needs.energy = Math.max(0, needs.energy - ENERGY_DECAY_PER_TICK * conMultiplier);
|
||||
needs.productivity = Math.max(0, needs.productivity - PRODUCTIVITY_DECAY_PER_TICK);
|
||||
|
||||
if (eventMemoryService) {
|
||||
if (prevHunger >= HUNGER_THRESHOLD && needs.hunger < HUNGER_THRESHOLD) {
|
||||
@@ -32,6 +34,15 @@ export function needsDecaySystem(world: World, eventMemoryService?: EventMemoryS
|
||||
detail: `${name} became exhausted`,
|
||||
});
|
||||
}
|
||||
if (prevProductivity >= PRODUCTIVITY_THRESHOLD && needs.productivity < PRODUCTIVITY_THRESHOLD) {
|
||||
const name = world.getComponent<string>(entity, 'name') ?? 'Unknown';
|
||||
eventMemoryService.record(entity, {
|
||||
type: 'need_crisis',
|
||||
tick: 0,
|
||||
need: 'productivity',
|
||||
detail: `${name} felt unproductive`,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user