import type { AccessorySlot, PortraitSlot } from './constants.js'; // Entity is just a numeric ID export type EntityId = number; // Components export interface Position { x: number; y: number; } export interface Velocity { dx: number; dy: number; } export interface Appearance { skinId: string; // e.g. "shape00_skin02" accessories: Partial>; // slot -> filename without extension portraitFeatures?: Partial>; // portrait-only facial features } export interface Needs { hunger: number; // 0-100 energy: number; // 0-100 } export type MovementState = 'idle' | 'walking'; export type GoalType = 'wander' | 'eat' | 'rest'; export interface Movement { state: MovementState; target: Position | null; path: Position[]; direction: number; // Direction enum value moveProgress: number; // fractional tile accumulator } export interface PlayerControlled { playerId: string; mode: 'avatar' | 'camera'; } export interface NPCBrain { currentGoal: GoalType | null; goalQueue: GoalType[]; } // Network protocol messages export interface EntityState { id: EntityId; position: Position; movement: Movement; appearance: Appearance; needs?: Needs; npcBrain?: NPCBrain; playerControlled?: PlayerControlled; name?: string; // NPC display name } export interface WorldState { entities: EntityState[]; worldWidth: number; worldHeight: number; tileSize: number; obstacles: Position[]; pointsOfInterest: { type: 'food' | 'rest'; position: Position }[]; } export interface StateUpdate { entities: EntityState[]; tick: number; } export interface PlayerJoined { playerId: string; entityId: EntityId; } export interface PlayerLeft { playerId: string; } export interface PlayerInput { type: 'move' | 'toggle-mode' | 'follow' | 'interact'; direction?: { dx: number; dy: number }; targetPlayerId?: string; targetEntityId?: EntityId; } // Server -> Client events export interface ServerEvents { 'world-state': (data: WorldState) => void; 'state-update': (data: StateUpdate) => void; 'player-joined': (data: PlayerJoined) => void; 'player-left': (data: PlayerLeft) => void; 'npc-recomposed': (data: { entityId: EntityId; appearance: Appearance }) => void; } // Client -> Server events export interface ClientEvents { 'player-input': (data: PlayerInput) => void; }