Home | History | Annotate | Line # | Download | only in adventure
io.c revision 1.14
      1 /*	$NetBSD: io.c,v 1.14 2003/09/19 10:01:21 itojun Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1991, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * The game adventure was originally written in Fortran by Will Crowther
      8  * and Don Woods.  It was later translated to C and enhanced by Jim
      9  * Gillogly.  This code is derived from software contributed to Berkeley
     10  * by Jim Gillogly at The Rand Corporation.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  * 1. Redistributions of source code must retain the above copyright
     16  *    notice, this list of conditions and the following disclaimer.
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  * 3. Neither the name of the University nor the names of its contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  */
     36 
     37 #include <sys/cdefs.h>
     38 #ifndef lint
     39 #if 0
     40 static char sccsid[] = "@(#)io.c	8.1 (Berkeley) 5/31/93";
     41 #else
     42 __RCSID("$NetBSD: io.c,v 1.14 2003/09/19 10:01:21 itojun Exp $");
     43 #endif
     44 #endif /* not lint */
     45 
     46 /*      Re-coding of advent in C: file i/o and user i/o                 */
     47 
     48 #include <err.h>
     49 #include <stdio.h>
     50 #include <string.h>
     51 #include <stdlib.h>
     52 #include "hdr.h"
     53 #include "extern.h"
     54 
     55 
     56 void
     57 getin(wrd1, wrd2)		/* get command from user        */
     58 	char  **wrd1, **wrd2;	/* no prompt, usually           */
     59 {
     60 	char   *s;
     61 	static char wd1buf[MAXSTR], wd2buf[MAXSTR];
     62 	int     first, numch;
     63 
     64 	*wrd1 = wd1buf;				/* return ptr to internal str */
     65 	*wrd2 = wd2buf;
     66 	wd2buf[0] = 0;				/* in case it isn't set here */
     67 	for (s = wd1buf, first = 1, numch = 0;;) {
     68 		if ((*s = getchar()) >= 'A' && *s <= 'Z')
     69 			*s = *s - ('A' - 'a');
     70 		/* convert to upper case */
     71 		switch (*s) {			/* start reading from user */
     72 		case '\n':
     73 			*s = 0;
     74 			return;
     75 		case ' ':
     76 			if (s == wd1buf || s == wd2buf)	/* initial blank */
     77 				continue;
     78 			*s = 0;
     79 			if (first) {		/* finished 1st wd; start 2nd */
     80 				first = numch = 0;
     81 				s = wd2buf;
     82 				break;
     83 			} else {		/* finished 2nd word */
     84 				FLUSHLINE;
     85 				*s = 0;
     86 				return;
     87 			}
     88 		case EOF:
     89 			printf("user closed input stream, quitting...\n");
     90 			exit(0);
     91 		default:
     92 			if (++numch >= MAXSTR) {	/* string too long */
     93 				printf("Give me a break!!\n");
     94 				wd1buf[0] = wd2buf[0] = 0;
     95 				FLUSHLINE;
     96 				return;
     97 			}
     98 			s++;
     99 		}
    100 	}
    101 }
    102 
    103 int
    104 yes(x, y, z)			/* confirm with rspeak          */
    105 	int     x, y, z;
    106 {
    107 	int     result = TRUE;	/* pacify gcc */
    108 	int    ch;
    109 	for (;;) {
    110 		rspeak(x);	/* tell him what we want */
    111 		if ((ch = getchar()) == 'y')
    112 			result = TRUE;
    113 		else if (ch == 'n')
    114 			result = FALSE;
    115 		else if (ch == EOF) {
    116 			printf("user closed input stream, quitting...\n");
    117 			exit(0);
    118 		}
    119 		FLUSHLINE;
    120 		if (ch == 'y' || ch == 'n')
    121 			break;
    122 		printf("Please answer the question.\n");
    123 	}
    124 	if (result == TRUE)
    125 		rspeak(y);
    126 	if (result == FALSE)
    127 		rspeak(z);
    128 	return (result);
    129 }
    130 
    131 int
    132 yesm(x, y, z)			/* confirm with mspeak          */
    133 	int     x, y, z;
    134 {
    135 	int     result = TRUE;	/* pacify gcc */
    136 	int    ch;
    137 	for (;;) {
    138 		mspeak(x);	/* tell him what we want */
    139 		if ((ch = getchar()) == 'y')
    140 			result = TRUE;
    141 		else if (ch == 'n')
    142 			result = FALSE;
    143 		else if (ch == EOF) {
    144 			printf("user closed input stream, quitting...\n");
    145 			exit(0);
    146 		}
    147 		FLUSHLINE;
    148 		if (ch == 'y' || ch == 'n')
    149 			break;
    150 		printf("Please answer the question.\n");
    151 	}
    152 	if (result == TRUE)
    153 		mspeak(y);
    154 	if (result == FALSE)
    155 		mspeak(z);
    156 	return (result);
    157 }
    158 /* FILE *inbuf,*outbuf; */
    159 
    160 char   *inptr;			/* Pointer into virtual disk    */
    161 
    162 int     outsw = 0;		/* putting stuff to data file?  */
    163 
    164 const char    iotape[] = "Ax3F'\003tt$8h\315qer*h\017nGKrX\207:!l";
    165 const char   *tape = iotape;		/* pointer to encryption tape   */
    166 
    167 int
    168 next()
    169 {				/* next virtual char, bump adr  */
    170 	int     ch;
    171 
    172 	ch = (*inptr ^ random()) & 0xFF;	/* Decrypt input data           */
    173 	if (outsw) {		/* putting data in tmp file     */
    174 		if (*tape == 0)
    175 			tape = iotape;	/* rewind encryption tape       */
    176 		*inptr = ch ^ *tape++;	/* re-encrypt and replace value */
    177 	}
    178 	inptr++;
    179 	return (ch);
    180 }
    181 
    182 char    breakch;		/* tell which char ended rnum   */
    183 
    184 void
    185 rdata()
    186 {				/* "read" data from virtual file */
    187 	int     sect;
    188 	char    ch;
    189 
    190 	inptr = data_file;	/* Pointer to virtual data file */
    191 	srandom(SEED);		/* which is lightly encrypted.  */
    192 
    193 	clsses = 1;
    194 	for (;;) {		/* read data sections           */
    195 		sect = next() - '0';	/* 1st digit of section number  */
    196 #ifdef VERBOSE
    197 		printf("Section %c", sect + '0');
    198 #endif
    199 		if ((ch = next()) != LF) {	/* is there a second digit?     */
    200 			FLUSHLF;
    201 #ifdef VERBOSE
    202 			putchar(ch);
    203 #endif
    204 			sect = 10 * sect + ch - '0';
    205 		}
    206 #ifdef VERBOSE
    207 		putchar('\n');
    208 #endif
    209 		switch (sect) {
    210 		case 0:	/* finished reading database    */
    211 			return;
    212 		case 1:	/* long form descriptions       */
    213 			rdesc(1);
    214 			break;
    215 		case 2:	/* short form descriptions      */
    216 			rdesc(2);
    217 			break;
    218 		case 3:	/* travel table                 */
    219 			rtrav();
    220 			break;
    221 		case 4:	/* vocabulary                   */
    222 			rvoc();
    223 			break;
    224 		case 5:	/* object descriptions          */
    225 			rdesc(5);
    226 			break;
    227 		case 6:	/* arbitrary messages           */
    228 			rdesc(6);
    229 			break;
    230 		case 7:	/* object locations             */
    231 			rlocs();
    232 			break;
    233 		case 8:	/* action defaults              */
    234 			rdflt();
    235 			break;
    236 		case 9:	/* liquid assets                */
    237 			rliq();
    238 			break;
    239 		case 10:	/* class messages               */
    240 			rdesc(10);
    241 			break;
    242 		case 11:	/* hints                        */
    243 			rhints();
    244 			break;
    245 		case 12:	/* magic messages               */
    246 			rdesc(12);
    247 			break;
    248 		default:
    249 			printf("Invalid data section number: %d\n", sect);
    250 			for (;;)
    251 				putchar(next());
    252 		}
    253 		if (breakch != LF)	/* routines return after "-1"   */
    254 			FLUSHLF;
    255 	}
    256 }
    257 
    258 char    nbf[12];
    259 
    260 
    261 int
    262 rnum()
    263 {				/* read initial location num    */
    264 	char   *s;
    265 	tape = iotape;		/* restart encryption tape      */
    266 	for (s = nbf, *s = 0;; s++)
    267 		if ((*s = next()) == TAB || *s == '\n' || *s == LF)
    268 			break;
    269 	breakch = *s;		/* save char for rtrav()        */
    270 	*s = 0;			/* got the number as ascii      */
    271 	if (nbf[0] == '-')
    272 		return (-1);	/* end of data                  */
    273 	return (atoi(nbf));	/* convert it to integer        */
    274 }
    275 
    276 char   *seekhere;
    277 
    278 void
    279 rdesc(sect)			/* read description-format msgs */
    280 	int     sect;
    281 {
    282 	int     locc;
    283 	char   *seekstart, *maystart;
    284 
    285 	seekhere = inptr;	/* Where are we in virtual file? */
    286 	outsw = 1;		/* these msgs go into tmp file  */
    287 	for (oldloc = -1, seekstart = seekhere;;) {
    288 		maystart = inptr;	/* maybe starting new entry     */
    289 		if ((locc = rnum()) != oldloc && oldloc >= 0	/* finished msg */
    290 		    && !(sect == 5 && (locc == 0 || locc >= 100))) {	/* unless sect 5 */
    291 			switch (sect) {	/* now put it into right table  */
    292 			case 1:/* long descriptions            */
    293 				ltext[oldloc].seekadr = seekhere;
    294 				ltext[oldloc].txtlen = maystart - seekstart;
    295 				break;
    296 			case 2:/* short descriptions           */
    297 				stext[oldloc].seekadr = seekhere;
    298 				stext[oldloc].txtlen = maystart - seekstart;
    299 				break;
    300 			case 5:/* object descriptions          */
    301 				ptext[oldloc].seekadr = seekhere;
    302 				ptext[oldloc].txtlen = maystart - seekstart;
    303 				break;
    304 			case 6:/* random messages              */
    305 				if (oldloc > RTXSIZ)
    306 					errx(1,"Too many random msgs");
    307 				rtext[oldloc].seekadr = seekhere;
    308 				rtext[oldloc].txtlen = maystart - seekstart;
    309 				break;
    310 			case 10:	/* class messages               */
    311 				ctext[clsses].seekadr = seekhere;
    312 				ctext[clsses].txtlen = maystart - seekstart;
    313 				cval[clsses++] = oldloc;
    314 				break;
    315 			case 12:	/* magic messages               */
    316 				if (oldloc >= MAGSIZ)
    317 					errx(1,"Too many magic msgs");
    318 				mtext[oldloc].seekadr = seekhere;
    319 				mtext[oldloc].txtlen = maystart - seekstart;
    320 				break;
    321 			default:
    322 				errx(1,"rdesc called with bad section");
    323 			}
    324 			seekhere += maystart - seekstart;
    325 		}
    326 		if (locc < 0) {
    327 			outsw = 0;	/* turn off output              */
    328 			seekhere += 3;	/* -1<delimiter>                */
    329 			return;
    330 		}
    331 		if (sect != 5 || (locc > 0 && locc < 100)) {
    332 			if (oldloc != locc)	/* starting a new message       */
    333 				seekstart = maystart;
    334 			oldloc = locc;
    335 		}
    336 		FLUSHLF;	/* scan the line                */
    337 	}
    338 }
    339 
    340 void
    341 rtrav()
    342 {				/* read travel table            */
    343 	int     locc;
    344 	struct travlist *t = NULL;
    345 	char   *s;
    346 	char    buf[12];
    347 	int     len, m, n, entries = 0;
    348 
    349 	for (oldloc = -1;;) {	/* get another line             */
    350 		if ((locc = rnum()) != oldloc && oldloc >= 0) {	/* end of entry */
    351 			t->next = 0;	/* terminate the old entry      */
    352 			/* printf("%d:%d entries\n",oldloc,entries);       */
    353 			/* twrite(oldloc);                                 */
    354 		}
    355 		if (locc == -1)
    356 			return;
    357 		if (locc != oldloc) {	/* getting a new entry         */
    358 			t = travel[locc] = (struct travlist *) malloc(sizeof(struct travlist));
    359 			if ( t == NULL)
    360 				err(1, NULL);
    361 			/* printf("New travel list for %d\n",locc);        */
    362 			entries = 0;
    363 			oldloc = locc;
    364 		}
    365 		for (s = buf;; s++)	/* get the newloc number /ASCII */
    366 			if ((*s = next()) == TAB || *s == LF)
    367 				break;
    368 		*s = 0;
    369 		len = length(buf) - 1;	/* quad long number handling    */
    370 		/* printf("Newloc: %s (%d chars)\n",buf,len);              */
    371 		if (len < 4) {	/* no "m" conditions            */
    372 			m = 0;
    373 			n = atoi(buf);	/* newloc mod 1000 = newloc     */
    374 		} else {	/* a long integer               */
    375 			n = atoi(buf + len - 3);
    376 			buf[len - 3] = 0;	/* terminate newloc/1000        */
    377 			m = atoi(buf);
    378 		}
    379 		while (breakch != LF) {	/* only do one line at a time   */
    380 			if (entries++) {
    381 				t = t->next = (struct travlist *) malloc(sizeof(struct travlist));
    382 				if (t == NULL)
    383 					err(1, NULL);
    384 			}
    385 			t->tverb = rnum();	/* get verb from the file       */
    386 			t->tloc = n;	/* table entry mod 1000         */
    387 			t->conditions = m;	/* table entry / 1000           */
    388 			/* printf("entry %d for %d\n",entries,locc);       */
    389 		}
    390 	}
    391 }
    392 #ifdef DEBUG
    393 
    394 void
    395 twrite(loq)			/* travel options from this loc */
    396 	int     loq;
    397 {
    398 	struct travlist *t;
    399 	printf("If");
    400 	speak(&ltext[loq]);
    401 	printf("then\n");
    402 	for (t = travel[loq]; t != 0; t = t->next) {
    403 		printf("verb %d takes you to ", t->tverb);
    404 		if (t->tloc <= 300)
    405 			speak(&ltext[t->tloc]);
    406 		else
    407 			if (t->tloc <= 500)
    408 				printf("special code %d\n", t->tloc - 300);
    409 			else
    410 				rspeak(t->tloc - 500);
    411 		printf("under conditions %d\n", t->conditions);
    412 	}
    413 }
    414 #endif				/* DEBUG */
    415 
    416 void
    417 rvoc()
    418 {
    419 	char   *s;		/* read the vocabulary          */
    420 	int     index;
    421 	char    buf[6];
    422 	for (;;) {
    423 		index = rnum();
    424 		if (index < 0)
    425 			break;
    426 		for (s = buf, *s = 0;; s++)	/* get the word                 */
    427 			if ((*s = next()) == TAB || *s == '\n' || *s == LF
    428 			    || *s == ' ')
    429 				break;
    430 		/* terminate word with newline, LF, tab, blank  */
    431 		if (*s != '\n' && *s != LF)
    432 			FLUSHLF;/* can be comments    */
    433 		*s = 0;
    434 		/* printf("\"%s\"=%d\n",buf,index); */
    435 		vocab(buf, -2, index);
    436 	}
    437 /*	prht();	*/
    438 }
    439 
    440 
    441 void
    442 rlocs()
    443 {				/* initial object locations     */
    444 	for (;;) {
    445 		if ((obj = rnum()) < 0)
    446 			break;
    447 		plac[obj] = rnum();	/* initial loc for this obj     */
    448 		if (breakch == TAB)	/* there's another entry        */
    449 			fixd[obj] = rnum();
    450 		else
    451 			fixd[obj] = 0;
    452 	}
    453 }
    454 
    455 void
    456 rdflt()
    457 {				/* default verb messages        */
    458 	for (;;) {
    459 		if ((verb = rnum()) < 0)
    460 			break;
    461 		actspk[verb] = rnum();
    462 	}
    463 }
    464 
    465 void
    466 rliq()
    467 {				/* liquid assets &c: cond bits  */
    468 	int     bitnum;
    469 	for (;;) {		/* read new bit list            */
    470 		if ((bitnum = rnum()) < 0)
    471 			break;
    472 		for (;;) {	/* read locs for bits           */
    473 			cond[rnum()] |= setbit[bitnum];
    474 			if (breakch == LF)
    475 				break;
    476 		}
    477 	}
    478 }
    479 
    480 void
    481 rhints()
    482 {
    483 	int     hintnum, i;
    484 	hntmax = 0;
    485 	for (;;) {
    486 		if ((hintnum = rnum()) < 0)
    487 			break;
    488 		for (i = 1; i < 5; i++)
    489 			hints[hintnum][i] = rnum();
    490 		if (hintnum > hntmax)
    491 			hntmax = hintnum;
    492 	}
    493 }
    494 
    495 
    496 void
    497 rspeak(msg)
    498 	int     msg;
    499 {
    500 	if (msg != 0)
    501 		speak(&rtext[msg]);
    502 }
    503 
    504 
    505 void
    506 mspeak(msg)
    507 	int     msg;
    508 {
    509 	if (msg != 0)
    510 		speak(&mtext[msg]);
    511 }
    512 
    513 
    514 void
    515 speak(msg)			/* read, decrypt, and print a message (not
    516 				 * ptext)      */
    517 	const struct text *msg;	/* msg is a pointer to seek address and length
    518 				 * of mess */
    519 {
    520 	char   *s, nonfirst;
    521 
    522 	s = msg->seekadr;
    523 	nonfirst = 0;
    524 	while (s - msg->seekadr < msg->txtlen) {	/* read a line at a time */
    525 		tape = iotape;	/* restart decryption tape      */
    526 		while ((*s++ ^ *tape++) != TAB);	/* read past loc num       */
    527 		/* assume tape is longer than location number           */
    528 		/* plus the lookahead put together                    */
    529 		if ((*s ^ *tape) == '>' &&
    530 		    (*(s + 1) ^ *(tape + 1)) == '$' &&
    531 		    (*(s + 2) ^ *(tape + 2)) == '<')
    532 			break;
    533 		if (blklin && !nonfirst++)
    534 			putchar('\n');
    535 		do {
    536 			if (*tape == 0)
    537 				tape = iotape;	/* rewind decryp tape */
    538 			putchar(*s ^ *tape);
    539 		} while ((*s++ ^ *tape++) != LF);	/* better end with LF   */
    540 	}
    541 }
    542 
    543 
    544 void
    545 pspeak(m, skip)			/* read, decrypt an print a ptext message              */
    546 	int     m;		/* msg is the number of all the p msgs for
    547 				 * this place  */
    548 	int     skip;		/* assumes object 1 doesn't have prop 1, obj 2
    549 				 * no prop 2 &c */
    550 {
    551 	char   *s, nonfirst;
    552 	char   *numst, save;
    553 	struct text *msg;
    554 	char   *tbuf;
    555 
    556 	msg = &ptext[m];
    557 	if ((tbuf = (char *) malloc(msg->txtlen + 1)) == NULL)
    558 		err(1, NULL);
    559 	memcpy(tbuf, msg->seekadr, msg->txtlen + 1);	/* Room to null */
    560 	s = tbuf;
    561 
    562 	nonfirst = 0;
    563 	while (s - tbuf < msg->txtlen) {	/* read line at a time */
    564 		tape = iotape;	/* restart decryption tape      */
    565 		for (numst = s; (*s ^= *tape++) != TAB; s++);	/* get number  */
    566 
    567 		save = *s;	/* Temporarily trash the string (cringe) */
    568 		*s++ = 0;	/* decrypting number within the string          */
    569 
    570 		if (atoi(numst) != 100 * skip && skip >= 0) {
    571 			while ((*s++ ^ *tape++) != LF)	/* flush the line    */
    572 				if (*tape == 0)
    573 					tape = iotape;
    574 			continue;
    575 		}
    576 		if ((*s ^ *tape) == '>' && (*(s + 1) ^ *(tape + 1)) == '$' &&
    577 		    (*(s + 2) ^ *(tape + 2)) == '<')
    578 			break;
    579 		if (blklin && !nonfirst++)
    580 			putchar('\n');
    581 		do {
    582 			if (*tape == 0)
    583 				tape = iotape;
    584 			putchar(*s ^ *tape);
    585 		} while ((*s++ ^ *tape++) != LF);	/* better end with LF   */
    586 		if (skip < 0)
    587 			break;
    588 	}
    589 	free(tbuf);
    590 }
    591