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