home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3086 < prev    next >
Encoding:
Internet Message Format  |  1991-03-17  |  12.5 KB

  1. From: linhart@cream.rutgers.edu (Mike Threepoint)
  2. Newsgroups: rec.games.misc,alt.sources,misc.misc
  3. Subject: Infocom(tm) adventure game vocabulary list dumper
  4. Message-ID: <Mar.16.11.51.42.1991.1920@cream.rutgers.edu>
  5. Date: 16 Mar 91 16:51:45 GMT
  6. Approved: nobody@remus.rutgers.edu
  7.  
  8. Hello sailor!
  9.  
  10. Introducing my latest hack...  
  11.  
  12. Having solved every Infocom adventure game except the 5 I don't have,
  13. what else was there to do but hack them?
  14.  
  15. This program extracts and translates the vocabulary list from the
  16. Infocom adventure game data files bundles with the interpreters.
  17. The data files should be the same format on any system.  The program
  18. should compile with only minor tweaks on any ANSI C compiler, but
  19. for UNIX you'll want to remove the `swab()' calls to swap the byte
  20. sex.
  21.  
  22. Enjoy...
  23.  
  24. <-- snip, snip
  25. /* vocab.c -- A data dumper
  26.  * Copyleft (c) 1991 by Mike Threepoint.  All rights reversed.
  27.  * Release 1 / Serial number 910310
  28.  *
  29.  * This program dumps the vocabulary list encoded in a standard Infocom(tm)
  30.  * adventure game data file.  Having solved all the Infocom games I have,
  31.  * there's little left to do but hack them.
  32.  *
  33.  * Go ahead, reassure yourself you've seen every last Encyclopedia Frobizzica
  34.  * entry, learned every spell, and know all the magic wand's F-words.
  35.  * Discover obscure synonyms (like calling the Zorkian elvish sword Glamdring
  36.  * and the dragon Smaug) and trivia about the game's internal operations
  37.  * (like the internal `intnum' noun in several games, used when you type a
  38.  * number).
  39.  *
  40.  * I doubt Infocom's employees will complain, either of them.  Alas, Infocom.
  41.  * I wore a black armband when you went under.  If only you'd stayed solvent.
  42.  * (At least till I could buy Sherlock and Arthur!  Can't purchase them
  43.  * anywhere anymore...)
  44.  *
  45.  * Email correspondence to linhart@remus.rutgers.edu.
  46.  *
  47.  * Disclaimer:  This program works for me, at the moment.  I've never seen
  48.  *              any Infocom source code(*), and nobody at 55 CambridgePark
  49.  *              Drive told me any technical details.  I'm just an independent
  50.  *              public domain software author.  If I-Need-Magic sues, I'll
  51.  *              cheerfully turn over all zero profits I made on this program.
  52.  *
  53.  * (* Well, maybe one function.  I noticed the Beyond Zork MS-DOS interpreter
  54.  *    was in MSC, so I mailed them a MSC function to get the screen size from
  55.  *    the BIOS instead of the stupid SETUP.EXE method, so the interpreter
  56.  *    could figure out when my VGA was in 50 line mode.  Some time later, a
  57.  *    new text game was released, with VisiClues.  I started it in 50-line
  58.  *    mode, but the screen was reset to 25-line CGA color mode.  And then the
  59.  *    text ran off the bottom of the screen and scrolled as if it were still
  60.  *    50 lines long.  I'd mail another helpful letter, but it's too late now.)
  61.  */
  62.  
  63. #define MAXCOL 79
  64.  
  65. #if !defined(__STDC__) && !defined(__TURBOC__)
  66. #error This is an ANSI-complaint.  It looks like you're not ANSI-compliant.
  67. #endif
  68.  
  69. #include <stdio.h>
  70. #include <stdlib.h>
  71. #include <stdarg.h>
  72. #include <string.h>
  73. #include <ctype.h>
  74.  
  75. #define S_BLANK         1
  76. #define S_MACRO1        2
  77. #define S_MACRO2        3
  78. #define S_MACRO3        4
  79. #define S_CAPS          5
  80. #define S_PUNC          6
  81. #define S_FILLER        6
  82. #define S_OFF           7
  83.  
  84. struct bits {
  85.         unsigned ch3 : 5;
  86.         unsigned ch2 : 5;
  87.         unsigned ch1 : 5;
  88.         unsigned     : 1;
  89. };
  90.  
  91. /* the 5-bit character set */
  92. const char err_chars[7] = {
  93.         /* null thrown in for string handling */
  94.         '\0',
  95.         /* special codes above */
  96.         ' ', '1', '2', '3', '^', '@',
  97.         /* followed by: */
  98. };
  99.  
  100. typedef const char alfabet[26];
  101.  
  102. alfabet
  103. lower = {
  104.         'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
  105.         'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
  106.         },
  107. upper = {
  108.         'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
  109.         'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
  110.         },
  111. punct = {
  112.         '$', ' ',
  113.         '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  114.         '.', ',', '!', '?', '_', '#', '\'', '\"', '/', '\\', '-', ':', '(', ')'
  115.         };
  116.  
  117. struct info_header {
  118.         char            type;
  119.         char            qqc;
  120.         unsigned        release;
  121.         unsigned        qqc3;
  122.         unsigned        qqc4;
  123.         unsigned        vocab_offset;
  124.         unsigned        off6;
  125.         unsigned        qqc7;
  126.         unsigned        qqc8;
  127.         unsigned        nul9;
  128.         char            rev_date[6];
  129.         unsigned        macro_offset;
  130.         unsigned        qqc14;
  131.         unsigned        qqc15;
  132.         unsigned        rest[17];
  133. };
  134.  
  135. FILE    *infile;
  136. short   column = 0;
  137. char    numbers = 1,
  138.         bits = 0,
  139.         wide = 1,
  140.         did_file = 0;
  141.  
  142.  
  143. void
  144. newline ( void )
  145. {
  146.         putchar('\n');
  147.         column = 0;
  148. }
  149.  
  150. char *
  151. bits_to_bstr ( struct bits *chars )
  152. {
  153.         static char buf[4] = {0, 0, 0, 0};
  154.  
  155.         buf[0] = chars->ch1 + 1;
  156.         buf[1] = chars->ch2 + 1;
  157.         buf[2] = chars->ch3 + 1;
  158.  
  159.         return buf;
  160. }
  161.  
  162. char *
  163. bstr_to_str ( char *s )
  164. {
  165.         int             len = strlen(s);
  166.         static char     new[MAXCOL+1];
  167.         unsigned        newlen = 0;
  168.  
  169.         while (s[len-1] == S_FILLER)
  170.                 s[--len] = '\0';
  171.  
  172.         while (*s) {
  173.                 switch (*s) {
  174.                         case S_MACRO1:
  175.                         case S_MACRO2:
  176.                         case S_MACRO3:
  177.                                 if (*s == S_MACRO1 && *(s+1) == S_CAPS) {
  178.                                         s++;
  179.                                         break;
  180.                                 }
  181.  
  182.                                 /* shouldn't appear in vocabulary list */
  183.                                 new [ newlen++ ] = err_chars[*s];
  184.                                 break;
  185.                         case S_CAPS:
  186.                                 if (*(s+1) >= S_OFF)
  187.                                         new [ newlen++ ] = upper[*(++s) - S_OFF];
  188.                                 else
  189.                                         new [ newlen++ ] = err_chars[S_CAPS];
  190.                                 break;
  191.                         case S_PUNC:
  192.                                 if (*(s+1) >= S_OFF)
  193.                                         new [ newlen++ ] = punct[*(++s) - S_OFF];
  194.                                 else
  195.                                         new [ newlen++ ] = err_chars[S_PUNC];
  196.                                 break;
  197.                         case S_BLANK:
  198.                                 new [ newlen++ ] = ' ';
  199.                                 break;
  200.                         default:
  201.                                 new [ newlen++ ] = lower[*s - S_OFF];
  202.                 }
  203.                 s++;
  204.         }
  205.  
  206.         new [ newlen ] = '\0';
  207.  
  208.         return new;
  209. }
  210.  
  211. void
  212. disp_ch ( char x )
  213. {
  214.         putchar(x);
  215.         column++;
  216. }
  217.  
  218. void
  219. disp_str ( char *fmt, ... )
  220. {
  221.         va_list         argptr;
  222.         static char     buf[16];
  223.         short           len;
  224.  
  225.         va_start(argptr, fmt);
  226.         vsprintf(buf, fmt, argptr);
  227.         va_end(argptr);
  228.  
  229.         len = strlen(buf);
  230.         if (column + len > MAXCOL)
  231.                 newline();
  232.         printf(buf);
  233.         column += len;
  234. }
  235.  
  236. void
  237. error ( char *fmt, ... )
  238. {
  239.         va_list         argptr;
  240.  
  241.         fprintf(stderr, "Error: ");
  242.  
  243.         va_start(argptr, fmt);
  244.         vfprintf(stderr, fmt, argptr);
  245.         va_end(argptr);
  246.  
  247.         exit(1);
  248. }
  249.  
  250. void
  251. disp_bits ( char c )
  252. {
  253.         disp_str(" %d%d%d%d%d%d%d%d",
  254.                  !!(c & 0x80),
  255.                  !!(c & 0x40),
  256.                  !!(c & 0x20),
  257.                  !!(c & 0x10),
  258.                  !!(c & 0x08),
  259.                  !!(c & 0x04),
  260.                  !!(c & 0x02),
  261.                  !!(c & 0x01));
  262. }
  263.  
  264. void
  265. frob_file ( const char *filename )
  266. {
  267.         register unsigned       count = 0;
  268.         unsigned                words;
  269.         unsigned                i;
  270.         unsigned char           ch, n;
  271.         struct bits             word[3];
  272.         char                    buf[10];
  273.         int                     entry_width;
  274.         struct info_header      header;
  275.         unsigned long           pos;
  276.  
  277.         if((infile = fopen(filename, "rb")) == NULL)
  278.                 error("Can't open \"%s\".\n", filename);
  279.  
  280.         printf("%s:\n", filename);
  281.  
  282.         fread(&header, sizeof(header), 1, infile);
  283.         swab((char *)&header.release, (char *)&i, 2);
  284.         printf("Release %u, updated %.6s\n", i, &header.rev_date[0]);
  285.  
  286.         swab((char *)&header.vocab_offset, (char *)&i, 2);
  287. #ifdef DEBUG
  288.         printf("Vocabulary table offset: %04X\n", i);
  289. #endif
  290.  
  291.         if (fseek(infile, pos = i, SEEK_SET) != 0)
  292.                 error("Can't seek offset %04X.\n", pos);
  293.  
  294.         /* skip leading info */
  295.         if (fread(&ch, sizeof(ch), 1, infile) < 1)
  296.                 error("Can't read character at offset %04X.\n", ftell(infile));
  297.  
  298.         if (fseek(infile, pos = ch, SEEK_CUR) != 0)
  299.                 error("Can't skip %ld characters from offset %04X.\n", pos, ftell(infile));
  300.  
  301.         fread(&ch, sizeof(ch), 1, infile);
  302.         /* 0x07 for 6 letters, 0x09 for 9 letters */
  303.         n = (ch < 9) ? 6 : 9;
  304.  
  305.         if (fread(&i, sizeof(i), 1, infile) < 1)
  306.                 error("Can't read word at offset %ld.\n", ftell(infile));
  307.         swab((char *)&i, (char *)&words, 2);
  308. #ifdef DEBUG
  309.         printf("Vocabulary entries: %d\n", words);
  310. #else
  311.         if (!numbers)
  312.                 printf("%d vocabulary entries\n", words);
  313. #endif
  314.  
  315.         entry_width = n;
  316.         n /= 3;
  317.  
  318.         if (numbers)
  319.                 entry_width += 5;
  320.         if (bits)
  321.                 entry_width += (wide ? 2 : 8) * 3 + 3;
  322.  
  323.         while ( count < words ) {
  324.                 if (fread(buf, sizeof(struct bits), n, infile) < n)
  325.                         error("Can't read vocabulary word at offset %ld.\n", ftell(infile));
  326.  
  327.                 swab(buf, (char *)&word, sizeof(struct bits) * n);
  328.  
  329.                 ++count;
  330.                 if (numbers)
  331.                         disp_str("%04d ", count);
  332.  
  333.                 strcpy(buf, bits_to_bstr(&word[0]));
  334.                 strcat(buf, bits_to_bstr(&word[1]));
  335.                 if (n >= 3)
  336.                         strcat(buf, bits_to_bstr(&word[2]));
  337.                 disp_str(n >= 3 ? "%-9s" : "%-6s", bstr_to_str(buf));
  338.  
  339.                 if (fread(buf, sizeof(char), 3, infile) < 3)
  340.                         error("Can't read vocabulary flags at offset %ld.\n", ftell(infile));
  341.  
  342.                 if (bits)
  343.                     if (wide)
  344.                            disp_str("  %02x %02x %02x", buf[1], buf[2], buf[3]);
  345.                     else {
  346.                            disp_ch(' ');
  347.                            disp_bits(buf[1]);
  348.                            disp_bits(buf[2]);
  349.                            disp_bits(buf[3]);
  350.                     }
  351.  
  352.                 if (wide && column + entry_width + 2 < MAXCOL)
  353.                         disp_str("  ");
  354.                 else
  355.                         newline();
  356.         }
  357.  
  358.         if (column)
  359.                 newline();
  360. }
  361.  
  362. #ifndef LINT
  363. const char sccsid[] = "@(#) " __FILE__ " by Mike Threepoint compiled " __DATE__;
  364. #endif
  365.  
  366. void
  367. info ( void )
  368. {
  369.         puts("Display a vocabulary list of an Infocom(tm) adventure game data file.\n"
  370.              "\n"
  371.              "Usage:  vocab [/#] [/1] [/b] file...\n"
  372.              "\n"
  373.              "\t/#   toggle numbers\n"
  374.              "\t/1   toggle one-column list\n"
  375.              "\t/b   toggle display of additional info encoded with each entry\n"
  376.              "\n");
  377.         exit(0);
  378. }
  379.  
  380. void
  381. parse ( char *parm )
  382. {
  383.         if (*parm == '-' || *parm == '/')
  384.                 switch (tolower(*++parm)) {
  385.                         case '#':
  386.                         case 'n':
  387.                                 numbers = !numbers;
  388.                                 break;
  389.                         case '1':
  390.                                 wide = !wide;
  391.                                 break;
  392.                         case 'b':
  393.                                 bits = !bits;
  394.                                 break;
  395.                         case 'h':
  396.                         case '?':
  397.                                 info();
  398.                 }
  399.         else {
  400.                 if (did_file) newline();
  401.                 frob_file(parm);
  402.                 did_file = 1;
  403.         }
  404. }
  405.  
  406. int
  407. main ( const unsigned argc, char *argv[] )
  408. {
  409.         if (argc > 1) {
  410.                 register count;
  411.  
  412.                 if (strcmp(argv[1], "?") == 0)
  413.                         info();
  414.  
  415.                 for (count = 1; count < argc; count++)
  416.                         parse(argv[count]);
  417.  
  418.                 if (did_file) return 0;
  419.         }
  420.  
  421.         info();
  422.         return 1;
  423. }
  424.