Checkpoint current interactive fiction state

This commit is contained in:
2026-05-14 21:17:43 +02:00
parent c745efd1d2
commit 873049f7e6
183 changed files with 13755 additions and 1459 deletions
+91 -11
View File
@@ -60,8 +60,17 @@ exports.io = io;
const DEFAULT_PORT = 3001;
const PORT = process.env.PORT ? parseInt(process.env.PORT) : DEFAULT_PORT;
const PORT_RANGE = 10; // Try up to 10 ports starting from the default
// Serve static files from the public directory
app.use(express_1.default.static(path_1.default.join(__dirname, '../public')));
// Serve static files from the public directory. Keep browser modules uncached
// during local development so fixes are visible without a hard cache clear.
app.use(express_1.default.static(path_1.default.join(__dirname, '../public'), {
etag: false,
lastModified: false,
setHeaders: (res) => {
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
res.setHeader('Pragma', 'no-cache');
res.setHeader('Expires', '0');
}
}));
// Test paragraphs to send to the client
const TEST_PARAGRAPHS = [
"You stand at the entrance of a mysterious cave. The air is cool and damp, carrying the scent of earth and ancient stone. Shadows dance on the walls as your torch flickers in the gentle breeze.",
@@ -72,16 +81,87 @@ const TEST_PARAGRAPHS = [
io.on('connection', (socket) => {
console.log(`New client connected: ${socket.id}`);
let currentParagraphIndex = 0;
let gameRunning = false;
const saveGames = new Set();
const startDemoGame = () => {
gameRunning = true;
currentParagraphIndex = 0;
socket.emit('gameIntroduction', {
introduction: "::chapter[Interactive Fiction Test]\n\nWelcome to the Interactive Fiction Test. This is a simplified version that sends predefined paragraphs instead of using an LLM.",
initialRoomDescription: TEST_PARAGRAPHS[0],
currentRoomId: "test-room"
});
};
const normalizeSaveSlot = (slot) => {
const value = Number(slot);
return Number.isInteger(value) && value > 0 ? value : 1;
};
socket.on('gameApi', (request, respond) => {
try {
const method = String(request?.method || '');
const args = Array.isArray(request?.args) ? request.args : [];
let response;
switch (method) {
case 'newGame':
case 'newGame()':
startDemoGame();
response = { success: true, result: true, running: true, canLoad: saveGames.size > 0 };
break;
case 'loadGame':
case 'loadGame()': {
const slot = normalizeSaveSlot(args[0]);
if (!saveGames.has(slot)) {
response = { success: false, error: 'missing_save', result: false };
break;
}
startDemoGame();
socket.emit('gameLoaded', { slot });
response = { success: true, result: true, running: true, slot };
break;
}
case 'saveGame':
case 'saveGame()': {
if (!gameRunning) {
response = { success: false, error: 'game_not_running', result: false };
break;
}
const slot = normalizeSaveSlot(args[0]);
saveGames.add(slot);
socket.emit('gameSaved', { slot });
response = { success: true, result: true, slot };
break;
}
case 'hasSaveGame':
case 'hasSaveGame()': {
const slot = normalizeSaveSlot(args[0]);
response = { success: true, result: saveGames.has(slot), slot };
break;
}
case 'getSaveGames':
case 'getSaveGames()':
response = { success: true, result: Array.from(saveGames).sort((a, b) => a - b) };
break;
case 'isGameRunning':
case 'isGameRunning()':
response = { success: true, result: gameRunning };
break;
default:
response = { success: false, error: `unknown_method:${method}` };
}
if (typeof respond === 'function')
respond(response);
}
catch (error) {
if (typeof respond === 'function') {
respond({ success: false, error: error instanceof Error ? error.message : String(error) });
}
}
});
// Start a new game
socket.on('startGame', async () => {
try {
console.log('Starting test game session');
// Send introduction to client
socket.emit('gameIntroduction', {
introduction: "Welcome to the Interactive Fiction Test. This is a simplified version that sends predefined paragraphs instead of using an LLM.",
initialRoomDescription: TEST_PARAGRAPHS[0],
currentRoomId: "test-room"
});
startDemoGame();
}
catch (error) {
console.error('Error starting game:', error);
@@ -92,11 +172,9 @@ io.on('connection', (socket) => {
socket.on('playerCommand', async (data) => {
try {
console.log(`Received command: ${data.command}`);
// Move to the next paragraph
currentParagraphIndex = (currentParagraphIndex + 1) % TEST_PARAGRAPHS.length;
// Send narrative response to client
socket.emit('narrativeResponse', {
text: TEST_PARAGRAPHS[currentParagraphIndex],
text: data.command,
gameState: {
currentRoomId: "test-room"
},
@@ -120,6 +198,8 @@ function ensureDirectories() {
path_1.default.join(__dirname, '../public/js'),
path_1.default.join(__dirname, '../public/css'),
path_1.default.join(__dirname, '../public/images'),
path_1.default.join(__dirname, '../public/music'),
path_1.default.join(__dirname, '../public/sounds'),
path_1.default.join(__dirname, '../public/fonts')
];
for (const dir of dirs) {