"use strict"; /** * Command-line interface for running the interactive fiction game */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.GameRunner = void 0; const readline = __importStar(require("readline")); const path = __importStar(require("path")); const dotenv = __importStar(require("dotenv")); const game_engine_1 = require("../engine/game-engine"); const openrouter_provider_1 = require("../llm/openrouter-provider"); // Load environment variables dotenv.config(); class GameRunner { constructor() { this.rl = null; this.gameContext = ''; this.gameHistory = []; this.suggestedCommands = []; this.engine = new game_engine_1.TextAdventureEngine(); this.llmProvider = new openrouter_provider_1.OpenRouterProvider(); } /** * Initialize the game */ async initialize(worldPath) { console.log('Initializing game...'); // Initialize LLM provider const apiKey = process.env.OPENROUTER_API_KEY; const model = process.env.OPENROUTER_MODEL; if (!apiKey || !model) { throw new Error('Missing required environment variables: OPENROUTER_API_KEY and/or OPENROUTER_MODEL'); } await this.llmProvider.initialize({ apiKey, model, temperature: 0.7, maxTokens: 800 }); // Load the world const resolvedPath = path.resolve(worldPath); console.log(`Loading world from ${resolvedPath}...`); await this.engine.loadWorld(resolvedPath); console.log('Game initialized successfully!'); } /** * Start the game in CLI mode */ async start() { // Create readline interface for CLI mode this.rl = readline.createInterface({ input: process.stdin, output: process.stdout }); try { // Display introduction const introText = await this.engine.start(); console.log('\n' + introText + '\n'); // Look at initial room const initialLook = this.engine.processAction({ action: 'look', confidence: 1 }); // Generate narrative description const narrativeRequest = { action: 'look', result: initialLook.message, roomDescription: this.engine.getCurrentRoomDescription(), visibleObjects: this.engine.getVisibleObjects(), visibleCharacters: this.engine.getVisibleCharacters(), tone: 'descriptive' }; const narrative = await this.llmProvider.generateNarrative(narrativeRequest); console.log('\n' + narrative.text + '\n'); // Store suggestions if available if (narrative.suggestions && narrative.suggestions.length > 0) { this.suggestedCommands = narrative.suggestions; } // Update game context this.updateGameContext(narrative.text); // Start the game loop this.gameLoop(); } catch (error) { console.error('Error starting game:', error); this.end(); } } /** * The main game loop for CLI mode */ gameLoop() { if (!this.rl) return; this.rl.question('> ', async (input) => { if (input.toLowerCase() === 'quit' || input.toLowerCase() === 'exit') { this.end(); return; } const response = await this.processCommand(input); console.log('\n' + response + '\n'); // Continue the game loop this.gameLoop(); }); } /** * Process a player command and return the narrative response * Used by both CLI and web interfaces */ async processCommand(input) { try { // Process player input const actionRequest = { playerInput: input, currentRoom: this.engine.getWorldModel().rooms[this.engine.getCurrentState().currentRoomId].name, visibleObjects: this.engine.getVisibleObjects().map(id => this.engine.getWorldModel().objects[id].name), visibleCharacters: this.engine.getVisibleCharacters().map(id => this.engine.getWorldModel().characters[id].name), possibleActions: this.engine.getAvailableActions(), inventory: this.engine.getCurrentState().inventory.map(id => this.engine.getWorldModel().objects[id].name), gameContext: this.gameContext }; if (this.rl) { console.log('Thinking...'); } // Translate player input to action const action = await this.llmProvider.translateAction(actionRequest); // Process the action in the game engine const actionResult = this.engine.processAction(action); // If state changed, update it if (actionResult.stateChanged && actionResult.newState) { this.engine.getCurrentState().currentRoomId = actionResult.newState.currentRoomId; this.engine.getCurrentState().inventory = actionResult.newState.inventory; this.engine.getCurrentState().visitedRooms = actionResult.newState.visitedRooms; this.engine.getCurrentState().flags = actionResult.newState.flags; this.engine.getCurrentState().counters = actionResult.newState.counters; } // Generate narrative description const narrativeRequest = { action: `${action.action}${action.object ? ' ' + action.object : ''}${action.target ? ' on ' + action.target : ''}`, result: actionResult.message, roomDescription: this.engine.getCurrentRoomDescription(), visibleObjects: this.engine.getVisibleObjects().map(id => this.engine.getWorldModel().objects[id].name), visibleCharacters: this.engine.getVisibleCharacters().map(id => this.engine.getWorldModel().characters[id].name), previousContext: this.gameHistory.slice(-3).join('\n'), tone: 'descriptive' }; const narrative = await this.llmProvider.generateNarrative(narrativeRequest); // Store suggestions if available if (narrative.suggestions && narrative.suggestions.length > 0) { this.suggestedCommands = narrative.suggestions; } // Update game context with the new narrative this.updateGameContext(narrative.text); // Return the narrative text return narrative.text; } catch (error) { console.error('Error processing input:', error); return 'Something went wrong. Please try again.'; } } /** * End the game */ end() { console.log('\nThanks for playing!'); if (this.rl) { this.rl.close(); this.rl = null; } this.engine.end(); if (process.env.NODE_ENV !== 'production') { process.exit(0); } } /** * Update the game context with new narrative */ updateGameContext(narrative) { // Add to history this.gameHistory.push(narrative); // Keep history limited to last 10 entries if (this.gameHistory.length > 10) { this.gameHistory.shift(); } // Update current context (last 5 entries) this.gameContext = this.gameHistory.slice(-5).join('\n'); } /** * Get the current game state * Used by web interface */ getGameState() { return { world: this.engine.getWorldModel(), currentRoomId: this.engine.getCurrentState().currentRoomId, inventory: this.engine.getCurrentState().inventory, visitedRooms: this.engine.getCurrentState().visitedRooms, flags: this.engine.getCurrentState().flags, counters: this.engine.getCurrentState().counters }; } /** * Get the current room description * Used by web interface */ getCurrentRoomDescription() { const roomId = this.engine.getCurrentState().currentRoomId; return this.engine.getWorldModel().rooms[roomId].description; } /** * Get suggested actions for the current game state * Used by web interface */ getSuggestions() { return this.suggestedCommands; } /** * Load a saved game state * Used by web interface */ loadGameState(savedState) { // Set the current state to match the saved state this.engine.getCurrentState().currentRoomId = savedState.currentRoomId; this.engine.getCurrentState().inventory = savedState.inventory; this.engine.getCurrentState().visitedRooms = savedState.visitedRooms; this.engine.getCurrentState().flags = savedState.flags; this.engine.getCurrentState().counters = savedState.counters; } } exports.GameRunner = GameRunner; //# sourceMappingURL=game-runner.js.map