feat: add baseline stat drift on social interaction outcomes
Positive social outcomes drift sociability and empathy up (+0.05), negative outcomes drift temperament up (+0.02), capped at 18. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -341,6 +341,37 @@ describe('socialSystem', () => {
|
||||
expect(saAfter.globalCooldown).toBe(40);
|
||||
});
|
||||
|
||||
it('drifts sociability and empathy on positive social outcome', () => {
|
||||
const world = new World();
|
||||
const a = createNPC(world, 5, 5);
|
||||
const b = createNPC(world, 8, 5);
|
||||
addStats(world, a, { sociability: 10.0, empathy: 10.0 });
|
||||
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 stats = world.getComponent<Stats>(a, 'stats')!;
|
||||
expect(stats.sociability).toBeCloseTo(10.05);
|
||||
expect(stats.empathy).toBeCloseTo(10.05);
|
||||
});
|
||||
|
||||
it('drifts temperament on negative social outcome', () => {
|
||||
const world = new World();
|
||||
const a = createNPC(world, 5, 5);
|
||||
const b = createNPC(world, 8, 5);
|
||||
addStats(world, a, { temperament: 10.0 });
|
||||
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 stats = world.getComponent<Stats>(a, 'stats')!;
|
||||
expect(stats.temperament).toBeCloseTo(10.02);
|
||||
});
|
||||
|
||||
it('high empathy biases positive outcome', () => {
|
||||
const world = new World();
|
||||
let positiveCount = 0;
|
||||
|
||||
@@ -3,6 +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,
|
||||
} from '@dflike/shared';
|
||||
import type { World } from '../ecs/World.js';
|
||||
import { getEffectiveStat } from './statHelpers.js';
|
||||
@@ -102,14 +103,36 @@ export function socialSystem(world: World): void {
|
||||
const socA = getEffectiveStat(world, e, 'sociability');
|
||||
social.globalCooldown = Math.round(SOCIAL_GLOBAL_COOLDOWN * (1 - (socA - 10) * 0.04));
|
||||
social.pairCooldowns.set(partnerId!, SOCIAL_PAIR_COOLDOWN);
|
||||
|
||||
const socB = getEffectiveStat(world, partnerId!, 'sociability');
|
||||
partnerSocial.globalCooldown = Math.round(SOCIAL_GLOBAL_COOLDOWN * (1 - (socB - 10) * 0.04));
|
||||
partnerSocial.pairCooldowns.set(e, SOCIAL_PAIR_COOLDOWN);
|
||||
|
||||
// Baseline stat drift
|
||||
const statsA = world.getComponent<Stats>(e, 'stats');
|
||||
if (statsA) {
|
||||
if (social.outcome === 'positive') {
|
||||
statsA.sociability = Math.min(18, statsA.sociability + 0.05);
|
||||
statsA.empathy = Math.min(18, statsA.empathy + 0.05);
|
||||
} else {
|
||||
statsA.temperament = Math.min(18, statsA.temperament + 0.02);
|
||||
}
|
||||
}
|
||||
const statsB = world.getComponent<Stats>(partnerId!, 'stats');
|
||||
if (statsB) {
|
||||
if (partnerSocial.outcome === 'positive') {
|
||||
statsB.sociability = Math.min(18, statsB.sociability + 0.05);
|
||||
statsB.empathy = Math.min(18, statsB.empathy + 0.05);
|
||||
} else {
|
||||
statsB.temperament = Math.min(18, statsB.temperament + 0.02);
|
||||
}
|
||||
}
|
||||
|
||||
social.phase = 'none';
|
||||
social.partnerId = null;
|
||||
social.phaseTimer = 0;
|
||||
social.outcome = null;
|
||||
|
||||
const socB = getEffectiveStat(world, partnerId!, 'sociability');
|
||||
partnerSocial.globalCooldown = Math.round(SOCIAL_GLOBAL_COOLDOWN * (1 - (socB - 10) * 0.04));
|
||||
partnerSocial.pairCooldowns.set(e, SOCIAL_PAIR_COOLDOWN);
|
||||
partnerSocial.phase = 'none';
|
||||
partnerSocial.partnerId = null;
|
||||
partnerSocial.phaseTimer = 0;
|
||||
|
||||
Reference in New Issue
Block a user