The Parser is Language Specific

Now sure if this is true in other platforms like Inform or TADS, but while designing Sharpee it became clear that the Parser makes a ton of assumptions about vocabulary and command structure that are directly tied to the language the author is using to tell their interactive story.

I already have a Language Provider package that hosts English messages and constants as 'lang-en-us'. It wasn't a huge leap to refactor the parser to be language specific as 'parser-en-us' and in its own package.

Then it was another very simple leap to how this works in a story. Here's an unimplemented sample piece of code that shows where this is going. Note this is using the standard library directly. We're still going to add another fluent layer so it's a simpler interface for authors.

The important part to highlight is the config object. You see language: 'en-us', which tells Sharpee to use the lang-en-us Language Provider package for messages and the parser-en-us Parser package for parsing player commands. If there are packages for lang-es-mx and parser-es-mx, then the author could configure language: 'es-mx' and create a Spanish language story.

// my-story.ts
import { Story, StoryConfig } from '@sharpee/engine';
import { WorldModel, IFEntity, EntityBuilder } from '@sharpee/world-model';

export class SpaceAdventureStory implements Story {
  config: StoryConfig = {
    id: 'space-adventure',
    title: 'Space Station Mystery',
    author: 'Jane Developer',
    version: '1.0.0',
    language: 'en-us',  // Uses English parser and language
    description: 'A mystery aboard a space station',
    tags: ['sci-fi', 'mystery', 'puzzle']
  };

  initializeWorld(world: WorldModel): void {
    // Create space station rooms
    const bridge = new EntityBuilder('bridge')
      .withName('Bridge')
      .withDescription('The command center of the space station.')
      .withTrait('if.trait.room')
      .build();
      
    const corridor = new EntityBuilder('corridor')
      .withName('Main Corridor')
      .withDescription('A long corridor with viewports showing stars.')
      .withTrait('if.trait.room')
      .build();
      
    world.addEntity(bridge);
    world.addEntity(corridor);
    
    // Connect rooms
    world.relate(bridge, 'if.rel.exit.south', corridor);
    world.relate(corridor, 'if.rel.exit.north', bridge);
  }

  createPlayer(world: WorldModel): IFEntity {
    const player = new EntityBuilder('player')
      .withName('Commander Blake')
      .withDescription('You are Commander Blake, investigating the mystery.')
      .withTrait('if.trait.player')
      .withTrait('if.trait.container')
      .build();
      
    // Start in the bridge
    const bridge = world.getEntity('bridge');
    if (bridge) {
      world.relate(player, 'if.rel.within', bridge);
    }
    
    return player;
  }

  getCustomActions() {
    // Story-specific actions
    return [
      {
        id: 'space-adventure.scan',
        patterns: ['scan', 'analyze'],
        execute: (context) => {
          // Custom scanning action
        }
      }
    ];
  }
}

I'm still working through custom messages and actions and how they get registered, mainly so the eventual Text Service can query everything and report the current state properly.

Subscribe to My So Called Interactive Fiction Life

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe