feat: add event-based transient stat modifiers on social outcomes

Positive outcomes add +1 sociability modifier (100 ticks).
Negative outcomes add -1 sociability and -1 empathy modifiers (100 ticks).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
root
2026-03-07 14:26:20 +00:00
parent 78cede4b32
commit c7b998dbd0
2 changed files with 56 additions and 1 deletions
@@ -372,6 +372,41 @@ describe('socialSystem', () => {
expect(stats.temperament).toBeCloseTo(10.02);
});
it('adds positive sociability modifier on positive outcome', () => {
const world = new World();
const a = createNPC(world, 5, 5);
const b = createNPC(world, 8, 5);
addStats(world, a);
addStats(world, b);
const sa = world.getComponent<SocialState>(a, 'socialState')!;
const sb = world.getComponent<SocialState>(b, 'socialState')!;
sa.phase = 'emoting'; sa.partnerId = b; sa.phaseTimer = 1; sa.outcome = 'positive';
sb.phase = 'emoting'; sb.partnerId = a; sb.phaseTimer = 1; sb.outcome = 'positive';
socialSystem(world);
const mods = world.getComponent<StatModifiers>(a, 'statModifiers')!;
const socMod = mods.modifiers.find(m => m.stat === 'sociability' && m.remaining === 100);
expect(socMod).toBeDefined();
expect(socMod!.value).toBe(1);
});
it('adds negative sociability and empathy modifiers on negative outcome', () => {
const world = new World();
const a = createNPC(world, 5, 5);
const b = createNPC(world, 8, 5);
addStats(world, a);
addStats(world, b);
const sa = world.getComponent<SocialState>(a, 'socialState')!;
const sb = world.getComponent<SocialState>(b, 'socialState')!;
sa.phase = 'emoting'; sa.partnerId = b; sa.phaseTimer = 1; sa.outcome = 'negative';
sb.phase = 'emoting'; sb.partnerId = a; sb.phaseTimer = 1; sb.outcome = 'negative';
socialSystem(world);
const mods = world.getComponent<StatModifiers>(a, 'statModifiers')!;
const socMod = mods.modifiers.find(m => m.stat === 'sociability' && m.remaining === 100);
const empMod = mods.modifiers.find(m => m.stat === 'empathy' && m.remaining === 100);
expect(socMod?.value).toBe(-1);
expect(empMod?.value).toBe(-1);
});
it('high empathy biases positive outcome', () => {
const world = new World();
let positiveCount = 0;
+21 -1
View File
@@ -3,7 +3,7 @@ import {
SOCIAL_GLOBAL_COOLDOWN, SOCIAL_PAIR_COOLDOWN,
HUNGER_THRESHOLD, ENERGY_THRESHOLD, Direction,
type SocialState, type Position, type Movement, type NPCBrain, type Needs, type EntityId,
type Stats,
type Stats, type StatModifiers,
} from '@dflike/shared';
import type { World } from '../ecs/World.js';
import { getEffectiveStat } from './statHelpers.js';
@@ -128,6 +128,26 @@ export function socialSystem(world: World): void {
}
}
// Event-based transient modifiers
const modsA = world.getComponent<StatModifiers>(e, 'statModifiers');
if (modsA) {
if (social.outcome === 'positive') {
modsA.modifiers.push({ stat: 'sociability', value: 1, remaining: 100 });
} else {
modsA.modifiers.push({ stat: 'sociability', value: -1, remaining: 100 });
modsA.modifiers.push({ stat: 'empathy', value: -1, remaining: 100 });
}
}
const modsB = world.getComponent<StatModifiers>(partnerId!, 'statModifiers');
if (modsB) {
if (partnerSocial.outcome === 'positive') {
modsB.modifiers.push({ stat: 'sociability', value: 1, remaining: 100 });
} else {
modsB.modifiers.push({ stat: 'sociability', value: -1, remaining: 100 });
modsB.modifiers.push({ stat: 'empathy', value: -1, remaining: 100 });
}
}
social.phase = 'none';
social.partnerId = null;
social.phaseTimer = 0;