import type { RoleActionDefinition, RoleAttributeProfile, RoleRelationState, } from './attributes'; import type {Character} from './characters'; import { AnimationState, type CharacterGender, type CombatActionMode, type CombatDelivery, type FacingDirection, type HostileNpcRenderAnimation, type NpcFunctionType, } from './core'; import type {InventoryItem} from './items'; export interface NpcPersistentState { affinity: number; relationState?: RoleRelationState; helpUsed: boolean; chattedCount: number; giftsGiven: number; inventory: InventoryItem[]; recruited: boolean; revealedFacts?: string[]; knownAttributeRumors?: string[]; firstMeaningfulContactResolved?: boolean; seenBackstoryChapterIds?: string[]; } export interface CompanionState { npcId: string; characterId: string; joinedAtAffinity: number; hp: number; maxHp: number; mana: number; maxMana: number; skillCooldowns: Record; animationState?: AnimationState; actionMode?: CombatActionMode; offsetX?: number; offsetY?: number; transitionMs?: number; } export interface CompanionRenderState { npcId: string; character: Character; hp: number; maxHp: number; mana: number; maxMana: number; skillCooldowns: Record; animationState: AnimationState; actionMode?: CombatActionMode; slot: 'upper' | 'lower'; facing?: FacingDirection; entryOffsetX?: number; entryOffsetY?: number; transitionMs?: number; recruitToken?: number; } export interface Encounter { id?: string; kind?: 'npc' | 'treasure'; npcName: string; npcDescription: string; npcAvatar: string; context: string; gender?: CharacterGender; specialBehavior?: 'initial_companion' | 'camp_companion'; xMeters?: number; characterId?: string; hostileNpcPresetId?: string; monsterPresetId?: string; initialAffinity?: number; hostile?: boolean; attributeProfile?: RoleAttributeProfile; } export interface SceneHostileNpc { id: string; name: string; action: string; description: string; animation: HostileNpcRenderAnimation; xMeters: number; yOffset: number; facing: FacingDirection; attackRange: number; speed: number; hp: number; maxHp: number; renderKind?: 'npc'; encounter?: Encounter; characterAnimation?: AnimationState; combatMode?: CombatDelivery; combatTags?: string[]; attributeProfile?: RoleAttributeProfile; behaviorVectors?: RoleActionDefinition[]; } export type SceneMonster = SceneHostileNpc; export interface SceneNpc { id: string; name: string; description: string; avatar: string; role: string; gender?: CharacterGender; characterId?: string; hostileNpcPresetId?: string; monsterPresetId?: string; initialAffinity?: number; hostile?: boolean; functions?: NpcFunctionType[]; recruitable?: boolean; attributeProfile?: RoleAttributeProfile; } export type SceneEncounterKind = 'npc' | 'treasure' | 'none'; export interface SceneEncounterResult { kind: SceneEncounterKind; npcId?: string; treasureText?: string; } export interface CombatVisualEffect { id: string; frames: string[]; fps: number; startX: number; endX?: number; startOrigin: 'player' | 'hostile_npc' | 'monster'; endOrigin?: 'player' | 'hostile_npc' | 'monster'; startMonsterId?: string; endMonsterId?: string; startHostileNpcId?: string; endHostileNpcId?: string; startAnchorOffsetY?: number; endAnchorOffsetY?: number; startOffsetX?: number; endOffsetX?: number; startYOffset: number; endYOffset?: number; durationMs: number; sizePx: number; scale?: number; facing: FacingDirection; zIndex?: number; traveling?: boolean; } export interface SceneHostileNpcChange { id: string; action: string; animation: HostileNpcRenderAnimation; moveMeters?: number; yOffset?: number; } export type SceneMonsterChange = SceneHostileNpcChange; export interface SceneDirective { playerAnimation: AnimationState; playerMoveMeters: number; playerOffsetY: number; playerFacing: FacingDirection; scrollWorld: boolean; monsterChanges: SceneMonsterChange[]; hostileNpcChanges?: SceneHostileNpcChange[]; } export interface ScenePresetInfo { id: string; name: string; description: string; imageSrc: string; forwardSceneId?: string; connectedSceneIds?: string[]; hostileNpcIds?: string[]; monsterIds?: string[]; npcs?: SceneNpc[]; treasureHints?: string[]; }