3a075b68e0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
98 lines
4.4 KiB
TypeScript
98 lines
4.4 KiB
TypeScript
import type {
|
|
EntityState, WorldState, StateUpdate,
|
|
Position, Movement, Appearance, Needs, NPCBrain, PlayerControlled, SocialState, Stats, Relationships,
|
|
} from '@dflike/shared';
|
|
import { TILE_SIZE } from '@dflike/shared';
|
|
import type { World } from '../ecs/World.js';
|
|
import type { GameMap } from '../map/GameMap.js';
|
|
import { getEffectiveStat } from '../systems/statHelpers.js';
|
|
import { getEffectiveClassification } from '../systems/relationshipHelpers.js';
|
|
import type { BondRegistry } from '../systems/bondRegistry.js';
|
|
import { hasBond } from '../systems/bondRegistry.js';
|
|
|
|
export function serializeEntity(world: World, entityId: number): EntityState {
|
|
const socialState = world.getComponent<SocialState>(entityId, 'socialState');
|
|
const statsComponent = world.getComponent<Stats>(entityId, 'stats');
|
|
const stats = statsComponent ? {
|
|
strength: getEffectiveStat(world, entityId, 'strength'),
|
|
dexterity: getEffectiveStat(world, entityId, 'dexterity'),
|
|
constitution: getEffectiveStat(world, entityId, 'constitution'),
|
|
intelligence: getEffectiveStat(world, entityId, 'intelligence'),
|
|
perception: getEffectiveStat(world, entityId, 'perception'),
|
|
sociability: getEffectiveStat(world, entityId, 'sociability'),
|
|
courage: getEffectiveStat(world, entityId, 'courage'),
|
|
curiosity: getEffectiveStat(world, entityId, 'curiosity'),
|
|
empathy: getEffectiveStat(world, entityId, 'empathy'),
|
|
temperament: getEffectiveStat(world, entityId, 'temperament'),
|
|
} : undefined;
|
|
const relationshipsComponent = world.getComponent<Relationships>(entityId, 'relationships');
|
|
const registry = world.getSingleton<BondRegistry>('bondRegistry');
|
|
const relationships = relationshipsComponent && relationshipsComponent.size > 0
|
|
? [...relationshipsComponent.entries()].map(([otherId, rel]) => {
|
|
const sociability = statsComponent ? getEffectiveStat(world, entityId, 'sociability') : 10;
|
|
const empathy = statsComponent ? getEffectiveStat(world, entityId, 'empathy') : 10;
|
|
const classification = getEffectiveClassification(
|
|
otherId, rel.value, relationshipsComponent, sociability, empathy,
|
|
registry, entityId,
|
|
);
|
|
let bond: string | null = null;
|
|
if (registry) {
|
|
if (hasBond(registry, entityId, otherId, 'partner')) bond = 'partner';
|
|
else if (hasBond(registry, entityId, otherId, 'partner', 'former')) bond = 'former_partner';
|
|
}
|
|
return {
|
|
entityId: otherId,
|
|
name: world.getComponent<string>(otherId, 'name') ?? `NPC #${otherId}`,
|
|
value: Math.round(rel.value * 10) / 10,
|
|
classification,
|
|
status: rel.status,
|
|
bond,
|
|
};
|
|
})
|
|
: undefined;
|
|
const inventoryComponent = world.getComponent<Map<string, number>>(entityId, 'inventory');
|
|
const inventory = inventoryComponent && inventoryComponent.size > 0
|
|
? Object.fromEntries(inventoryComponent)
|
|
: undefined;
|
|
return {
|
|
id: entityId,
|
|
position: world.getComponent<Position>(entityId, 'position')!,
|
|
movement: world.getComponent<Movement>(entityId, 'movement')!,
|
|
appearance: world.getComponent<Appearance>(entityId, 'appearance')!,
|
|
needs: world.getComponent<Needs>(entityId, 'needs'),
|
|
npcBrain: world.getComponent<NPCBrain>(entityId, 'npcBrain'),
|
|
playerControlled: world.getComponent<PlayerControlled>(entityId, 'playerControlled'),
|
|
name: world.getComponent<string>(entityId, 'name'),
|
|
backstory: world.getComponent<string>(entityId, 'backstory') || undefined,
|
|
socialState: socialState ? {
|
|
phase: socialState.phase,
|
|
partnerId: socialState.partnerId,
|
|
outcome: socialState.outcome,
|
|
} : undefined,
|
|
stats,
|
|
relationships,
|
|
inventory,
|
|
};
|
|
}
|
|
|
|
export function serializeWorldState(world: World, map: GameMap): WorldState {
|
|
const entities = world.query('position').map(id => serializeEntity(world, id));
|
|
return {
|
|
entities,
|
|
worldWidth: map.width,
|
|
worldHeight: map.height,
|
|
tileSize: TILE_SIZE,
|
|
obstacles: map.getObstacles(),
|
|
pointsOfInterest: map.getPointsOfInterest(),
|
|
terrain: map.terrain,
|
|
decorations: map.decorations,
|
|
trunkDecorations: map.trunkDecorations,
|
|
resourceTiles: map.resourceTiles,
|
|
};
|
|
}
|
|
|
|
export function serializeStateUpdate(world: World, tick: number, gameTime: number): StateUpdate {
|
|
const entities = world.query('position').map(id => serializeEntity(world, id));
|
|
return { entities, tick, gameTime };
|
|
}
|