home *** CD-ROM | disk | FTP | other *** search
- From: linhart@cream.rutgers.edu (Mike Threepoint)
- Newsgroups: rec.games.misc,alt.sources,misc.misc
- Subject: Infocom(tm) adventure game vocabulary list dumper
- Message-ID: <Mar.16.11.51.42.1991.1920@cream.rutgers.edu>
- Date: 16 Mar 91 16:51:45 GMT
- Approved: nobody@remus.rutgers.edu
-
- Hello sailor!
-
- Introducing my latest hack...
-
- Having solved every Infocom adventure game except the 5 I don't have,
- what else was there to do but hack them?
-
- This program extracts and translates the vocabulary list from the
- Infocom adventure game data files bundles with the interpreters.
- The data files should be the same format on any system. The program
- should compile with only minor tweaks on any ANSI C compiler, but
- for UNIX you'll want to remove the `swab()' calls to swap the byte
- sex.
-
- Enjoy...
-
- <-- snip, snip
- /* vocab.c -- A data dumper
- * Copyleft (c) 1991 by Mike Threepoint. All rights reversed.
- * Release 1 / Serial number 910310
- *
- * This program dumps the vocabulary list encoded in a standard Infocom(tm)
- * adventure game data file. Having solved all the Infocom games I have,
- * there's little left to do but hack them.
- *
- * Go ahead, reassure yourself you've seen every last Encyclopedia Frobizzica
- * entry, learned every spell, and know all the magic wand's F-words.
- * Discover obscure synonyms (like calling the Zorkian elvish sword Glamdring
- * and the dragon Smaug) and trivia about the game's internal operations
- * (like the internal `intnum' noun in several games, used when you type a
- * number).
- *
- * I doubt Infocom's employees will complain, either of them. Alas, Infocom.
- * I wore a black armband when you went under. If only you'd stayed solvent.
- * (At least till I could buy Sherlock and Arthur! Can't purchase them
- * anywhere anymore...)
- *
- * Email correspondence to linhart@remus.rutgers.edu.
- *
- * Disclaimer: This program works for me, at the moment. I've never seen
- * any Infocom source code(*), and nobody at 55 CambridgePark
- * Drive told me any technical details. I'm just an independent
- * public domain software author. If I-Need-Magic sues, I'll
- * cheerfully turn over all zero profits I made on this program.
- *
- * (* Well, maybe one function. I noticed the Beyond Zork MS-DOS interpreter
- * was in MSC, so I mailed them a MSC function to get the screen size from
- * the BIOS instead of the stupid SETUP.EXE method, so the interpreter
- * could figure out when my VGA was in 50 line mode. Some time later, a
- * new text game was released, with VisiClues. I started it in 50-line
- * mode, but the screen was reset to 25-line CGA color mode. And then the
- * text ran off the bottom of the screen and scrolled as if it were still
- * 50 lines long. I'd mail another helpful letter, but it's too late now.)
- */
-
- #define MAXCOL 79
-
- #if !defined(__STDC__) && !defined(__TURBOC__)
- #error This is an ANSI-complaint. It looks like you're not ANSI-compliant.
- #endif
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <string.h>
- #include <ctype.h>
-
- #define S_BLANK 1
- #define S_MACRO1 2
- #define S_MACRO2 3
- #define S_MACRO3 4
- #define S_CAPS 5
- #define S_PUNC 6
- #define S_FILLER 6
- #define S_OFF 7
-
- struct bits {
- unsigned ch3 : 5;
- unsigned ch2 : 5;
- unsigned ch1 : 5;
- unsigned : 1;
- };
-
- /* the 5-bit character set */
- const char err_chars[7] = {
- /* null thrown in for string handling */
- '\0',
- /* special codes above */
- ' ', '1', '2', '3', '^', '@',
- /* followed by: */
- };
-
- typedef const char alfabet[26];
-
- alfabet
- lower = {
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
- 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
- },
- upper = {
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
- 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
- },
- punct = {
- '$', ' ',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- '.', ',', '!', '?', '_', '#', '\'', '\"', '/', '\\', '-', ':', '(', ')'
- };
-
- struct info_header {
- char type;
- char qqc;
- unsigned release;
- unsigned qqc3;
- unsigned qqc4;
- unsigned vocab_offset;
- unsigned off6;
- unsigned qqc7;
- unsigned qqc8;
- unsigned nul9;
- char rev_date[6];
- unsigned macro_offset;
- unsigned qqc14;
- unsigned qqc15;
- unsigned rest[17];
- };
-
- FILE *infile;
- short column = 0;
- char numbers = 1,
- bits = 0,
- wide = 1,
- did_file = 0;
-
-
- void
- newline ( void )
- {
- putchar('\n');
- column = 0;
- }
-
- char *
- bits_to_bstr ( struct bits *chars )
- {
- static char buf[4] = {0, 0, 0, 0};
-
- buf[0] = chars->ch1 + 1;
- buf[1] = chars->ch2 + 1;
- buf[2] = chars->ch3 + 1;
-
- return buf;
- }
-
- char *
- bstr_to_str ( char *s )
- {
- int len = strlen(s);
- static char new[MAXCOL+1];
- unsigned newlen = 0;
-
- while (s[len-1] == S_FILLER)
- s[--len] = '\0';
-
- while (*s) {
- switch (*s) {
- case S_MACRO1:
- case S_MACRO2:
- case S_MACRO3:
- if (*s == S_MACRO1 && *(s+1) == S_CAPS) {
- s++;
- break;
- }
-
- /* shouldn't appear in vocabulary list */
- new [ newlen++ ] = err_chars[*s];
- break;
- case S_CAPS:
- if (*(s+1) >= S_OFF)
- new [ newlen++ ] = upper[*(++s) - S_OFF];
- else
- new [ newlen++ ] = err_chars[S_CAPS];
- break;
- case S_PUNC:
- if (*(s+1) >= S_OFF)
- new [ newlen++ ] = punct[*(++s) - S_OFF];
- else
- new [ newlen++ ] = err_chars[S_PUNC];
- break;
- case S_BLANK:
- new [ newlen++ ] = ' ';
- break;
- default:
- new [ newlen++ ] = lower[*s - S_OFF];
- }
- s++;
- }
-
- new [ newlen ] = '\0';
-
- return new;
- }
-
- void
- disp_ch ( char x )
- {
- putchar(x);
- column++;
- }
-
- void
- disp_str ( char *fmt, ... )
- {
- va_list argptr;
- static char buf[16];
- short len;
-
- va_start(argptr, fmt);
- vsprintf(buf, fmt, argptr);
- va_end(argptr);
-
- len = strlen(buf);
- if (column + len > MAXCOL)
- newline();
- printf(buf);
- column += len;
- }
-
- void
- error ( char *fmt, ... )
- {
- va_list argptr;
-
- fprintf(stderr, "Error: ");
-
- va_start(argptr, fmt);
- vfprintf(stderr, fmt, argptr);
- va_end(argptr);
-
- exit(1);
- }
-
- void
- disp_bits ( char c )
- {
- disp_str(" %d%d%d%d%d%d%d%d",
- !!(c & 0x80),
- !!(c & 0x40),
- !!(c & 0x20),
- !!(c & 0x10),
- !!(c & 0x08),
- !!(c & 0x04),
- !!(c & 0x02),
- !!(c & 0x01));
- }
-
- void
- frob_file ( const char *filename )
- {
- register unsigned count = 0;
- unsigned words;
- unsigned i;
- unsigned char ch, n;
- struct bits word[3];
- char buf[10];
- int entry_width;
- struct info_header header;
- unsigned long pos;
-
- if((infile = fopen(filename, "rb")) == NULL)
- error("Can't open \"%s\".\n", filename);
-
- printf("%s:\n", filename);
-
- fread(&header, sizeof(header), 1, infile);
- swab((char *)&header.release, (char *)&i, 2);
- printf("Release %u, updated %.6s\n", i, &header.rev_date[0]);
-
- swab((char *)&header.vocab_offset, (char *)&i, 2);
- #ifdef DEBUG
- printf("Vocabulary table offset: %04X\n", i);
- #endif
-
- if (fseek(infile, pos = i, SEEK_SET) != 0)
- error("Can't seek offset %04X.\n", pos);
-
- /* skip leading info */
- if (fread(&ch, sizeof(ch), 1, infile) < 1)
- error("Can't read character at offset %04X.\n", ftell(infile));
-
- if (fseek(infile, pos = ch, SEEK_CUR) != 0)
- error("Can't skip %ld characters from offset %04X.\n", pos, ftell(infile));
-
- fread(&ch, sizeof(ch), 1, infile);
- /* 0x07 for 6 letters, 0x09 for 9 letters */
- n = (ch < 9) ? 6 : 9;
-
- if (fread(&i, sizeof(i), 1, infile) < 1)
- error("Can't read word at offset %ld.\n", ftell(infile));
- swab((char *)&i, (char *)&words, 2);
- #ifdef DEBUG
- printf("Vocabulary entries: %d\n", words);
- #else
- if (!numbers)
- printf("%d vocabulary entries\n", words);
- #endif
-
- entry_width = n;
- n /= 3;
-
- if (numbers)
- entry_width += 5;
- if (bits)
- entry_width += (wide ? 2 : 8) * 3 + 3;
-
- while ( count < words ) {
- if (fread(buf, sizeof(struct bits), n, infile) < n)
- error("Can't read vocabulary word at offset %ld.\n", ftell(infile));
-
- swab(buf, (char *)&word, sizeof(struct bits) * n);
-
- ++count;
- if (numbers)
- disp_str("%04d ", count);
-
- strcpy(buf, bits_to_bstr(&word[0]));
- strcat(buf, bits_to_bstr(&word[1]));
- if (n >= 3)
- strcat(buf, bits_to_bstr(&word[2]));
- disp_str(n >= 3 ? "%-9s" : "%-6s", bstr_to_str(buf));
-
- if (fread(buf, sizeof(char), 3, infile) < 3)
- error("Can't read vocabulary flags at offset %ld.\n", ftell(infile));
-
- if (bits)
- if (wide)
- disp_str(" %02x %02x %02x", buf[1], buf[2], buf[3]);
- else {
- disp_ch(' ');
- disp_bits(buf[1]);
- disp_bits(buf[2]);
- disp_bits(buf[3]);
- }
-
- if (wide && column + entry_width + 2 < MAXCOL)
- disp_str(" ");
- else
- newline();
- }
-
- if (column)
- newline();
- }
-
- #ifndef LINT
- const char sccsid[] = "@(#) " __FILE__ " by Mike Threepoint compiled " __DATE__;
- #endif
-
- void
- info ( void )
- {
- puts("Display a vocabulary list of an Infocom(tm) adventure game data file.\n"
- "\n"
- "Usage: vocab [/#] [/1] [/b] file...\n"
- "\n"
- "\t/# toggle numbers\n"
- "\t/1 toggle one-column list\n"
- "\t/b toggle display of additional info encoded with each entry\n"
- "\n");
- exit(0);
- }
-
- void
- parse ( char *parm )
- {
- if (*parm == '-' || *parm == '/')
- switch (tolower(*++parm)) {
- case '#':
- case 'n':
- numbers = !numbers;
- break;
- case '1':
- wide = !wide;
- break;
- case 'b':
- bits = !bits;
- break;
- case 'h':
- case '?':
- info();
- }
- else {
- if (did_file) newline();
- frob_file(parm);
- did_file = 1;
- }
- }
-
- int
- main ( const unsigned argc, char *argv[] )
- {
- if (argc > 1) {
- register count;
-
- if (strcmp(argv[1], "?") == 0)
- info();
-
- for (count = 1; count < argc; count++)
- parse(argv[count]);
-
- if (did_file) return 0;
- }
-
- info();
- return 1;
- }
-