0cf48ded61
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
104 lines
2.3 KiB
TypeScript
104 lines
2.3 KiB
TypeScript
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<Record<AccessorySlot, string>>; // slot -> filename without extension
|
|
portraitFeatures?: Partial<Record<PortraitSlot, string>>; // 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;
|
|
}
|