147851Sbostic /*-
2*60732Sbostic * Copyright (c) 1991, 1993
3*60732Sbostic * The Regents of the University of California. All rights reserved.
447851Sbostic *
559968Sbostic * The game adventure was originally written in Fortran by Will Crowther
659968Sbostic * and Don Woods. It was later translated to C and enhanced by Jim
759968Sbostic * Gillogly. This code is derived from software contributed to Berkeley
859968Sbostic * by Jim Gillogly at The Rand Corporation.
947851Sbostic *
1047851Sbostic * %sccs.include.redist.c%
1147851Sbostic */
1247851Sbostic
1347851Sbostic #ifndef lint
14*60732Sbostic static char sccsid[] = "@(#)io.c 8.1 (Berkeley) 05/31/93";
1547851Sbostic #endif /* not lint */
1647851Sbostic
176736Srrh /* Re-coding of advent in C: file i/o and user i/o */
186736Srrh
196736Srrh #include "hdr.h"
206736Srrh #include <stdio.h>
216736Srrh
226736Srrh
getin(wrd1,wrd2)236736Srrh getin(wrd1,wrd2) /* get command from user */
246736Srrh char **wrd1,**wrd2; /* no prompt, usually */
256736Srrh { register char *s;
266736Srrh static char wd1buf[MAXSTR],wd2buf[MAXSTR];
276736Srrh int first, numch;
286736Srrh
296736Srrh *wrd1=wd1buf; /* return ptr to internal string*/
306736Srrh *wrd2=wd2buf;
316736Srrh wd2buf[0]=0; /* in case it isn't set here */
326736Srrh for (s=wd1buf, first=1, numch=0;;)
336736Srrh { if ((*s=getchar())>='A' && *s <='Z') *s = *s - ('A' -'a');
346736Srrh /* convert to upper case */
356736Srrh switch(*s) /* start reading from user */
366736Srrh { case '\n':
376736Srrh *s=0;
386736Srrh return;
396736Srrh case ' ':
406736Srrh if (s==wd1buf||s==wd2buf) /* initial blank */
416736Srrh continue;
426736Srrh *s=0;
436736Srrh if (first) /* finished 1st wd; start 2nd */
446736Srrh { first=numch=0;
456736Srrh s=wd2buf;
466736Srrh break;
476736Srrh }
486736Srrh else /* finished 2nd word */
496736Srrh { FLUSHLINE;
506736Srrh *s=0;
516736Srrh return;
526736Srrh }
536736Srrh default:
546736Srrh if (++numch>=MAXSTR) /* string too long */
556736Srrh { printf("Give me a break!!\n");
566736Srrh wd1buf[0]=wd2buf[0]=0;
576736Srrh FLUSHLINE;
586736Srrh return;
596736Srrh }
606736Srrh s++;
616736Srrh }
626736Srrh }
636736Srrh }
646736Srrh
656736Srrh
confirm(mesg)666736Srrh confirm(mesg) /* confirm irreversible action */
676736Srrh char *mesg;
686736Srrh { register int result;
696736Srrh printf("%s",mesg); /* tell him what he did */
706736Srrh if (getchar()=='y') /* was his first letter a 'y'? */
716736Srrh result=1;
726736Srrh else result=0;
736736Srrh FLUSHLINE;
746736Srrh return(result);
756736Srrh }
766736Srrh
yes(x,y,z)776736Srrh yes(x,y,z) /* confirm with rspeak */
786736Srrh int x,y,z;
796736Srrh { register int result;
806736Srrh register char ch;
816736Srrh for (;;)
826736Srrh { rspeak(x); /* tell him what we want*/
836736Srrh if ((ch=getchar())=='y')
846736Srrh result=TRUE;
856736Srrh else if (ch=='n') result=FALSE;
866736Srrh FLUSHLINE;
876736Srrh if (ch=='y'|| ch=='n') break;
886736Srrh printf("Please answer the question.\n");
896736Srrh }
906736Srrh if (result==TRUE) rspeak(y);
916736Srrh if (result==FALSE) rspeak(z);
926736Srrh return(result);
936736Srrh }
946736Srrh
yesm(x,y,z)956736Srrh yesm(x,y,z) /* confirm with mspeak */
966736Srrh int x,y,z;
976736Srrh { register int result;
986736Srrh register char ch;
996736Srrh for (;;)
1006736Srrh { mspeak(x); /* tell him what we want*/
1016736Srrh if ((ch=getchar())=='y')
1026736Srrh result=TRUE;
1036736Srrh else if (ch=='n') result=FALSE;
1046736Srrh FLUSHLINE;
1056736Srrh if (ch=='y'|| ch=='n') break;
1066736Srrh printf("Please answer the question.\n");
1076736Srrh }
1086736Srrh if (result==TRUE) mspeak(y);
1096736Srrh if (result==FALSE) mspeak(z);
1106736Srrh return(result);
1116736Srrh }
1126736Srrh
11359968Sbostic /* FILE *inbuf,*outbuf; */
1146736Srrh
11559968Sbostic char *inptr; /* Pointer into virtual disk */
11659968Sbostic
1176736Srrh int outsw = 0; /* putting stuff to data file? */
1186736Srrh
11959968Sbostic char iotape[] = "Ax3F'\003tt$8h\315qer*h\017nGKrX\207:!l";
1206736Srrh char *tape = iotape; /* pointer to encryption tape */
1216736Srrh
next()12259968Sbostic next() /* next virtual char, bump adr */
12359968Sbostic {
12459968Sbostic int ch;
12559968Sbostic
12659968Sbostic ch=(*inptr ^ random()) & 0xFF; /* Decrypt input data */
1276736Srrh if (outsw) /* putting data in tmp file */
12859968Sbostic { if (*tape==0) tape=iotape; /* rewind encryption tape */
12959968Sbostic *inptr = ch ^ *tape++; /* re-encrypt and replace value */
1306736Srrh }
13159968Sbostic inptr++;
1326736Srrh return(ch);
1336736Srrh }
1346736Srrh
1356736Srrh char breakch; /* tell which char ended rnum */
1366736Srrh
rdata()13759968Sbostic rdata() /* "read" data from virtual file*/
1386736Srrh { register int sect;
1396736Srrh register char ch;
14059968Sbostic
14159968Sbostic inptr = data_file; /* Pointer to virtual data file */
14259968Sbostic srandom(SEED); /* which is lightly encrypted. */
14359968Sbostic
14459968Sbostic clsses=1;
1456736Srrh for (;;) /* read data sections */
1466736Srrh { sect=next()-'0'; /* 1st digit of section number */
14759968Sbostic #ifdef VERBOSE
1486736Srrh printf("Section %c",sect+'0');
14959968Sbostic #endif
1506736Srrh if ((ch=next())!=LF) /* is there a second digit? */
15159968Sbostic {
15259968Sbostic FLUSHLF;
15359968Sbostic #ifdef VERBOSE
1546736Srrh putchar(ch);
15559968Sbostic #endif
1566736Srrh sect=10*sect+ch-'0';
1576736Srrh }
15859968Sbostic #ifdef VERBOSE
1596736Srrh putchar('\n');
16059968Sbostic #endif
1616736Srrh switch(sect)
1626736Srrh { case 0: /* finished reading database */
1636736Srrh return;
1646736Srrh case 1: /* long form descriptions */
1656736Srrh rdesc(1);
1666736Srrh break;
1676736Srrh case 2: /* short form descriptions */
1686736Srrh rdesc(2);
1696736Srrh break;
1706736Srrh case 3: /* travel table */
1716736Srrh rtrav(); break;
1726736Srrh case 4: /* vocabulary */
1736736Srrh rvoc();
1746736Srrh break;
1756736Srrh case 5: /* object descriptions */
1766736Srrh rdesc(5);
1776736Srrh break;
1786736Srrh case 6: /* arbitrary messages */
1796736Srrh rdesc(6);
1806736Srrh break;
1816736Srrh case 7: /* object locations */
1826736Srrh rlocs(); break;
1836736Srrh case 8: /* action defaults */
1846736Srrh rdflt(); break;
1856736Srrh case 9: /* liquid assets */
1866736Srrh rliq(); break;
1876736Srrh case 10: /* class messages */
1886736Srrh rdesc(10);
1896736Srrh break;
1906736Srrh case 11: /* hints */
1916736Srrh rhints(); break;
1926736Srrh case 12: /* magic messages */
1936736Srrh rdesc(12);
1946736Srrh break;
1956736Srrh default:
1966736Srrh printf("Invalid data section number: %d\n",sect);
1976736Srrh for (;;) putchar(next());
1986736Srrh }
1996736Srrh if (breakch!=LF) /* routines return after "-1" */
2006736Srrh FLUSHLF;
2016736Srrh }
2026736Srrh }
2036736Srrh
2046736Srrh char nbf[12];
2056736Srrh
2066736Srrh
rnum()2076736Srrh rnum() /* read initial location num */
2086736Srrh { register char *s;
2096736Srrh tape = iotape; /* restart encryption tape */
2106736Srrh for (s=nbf,*s=0;; s++)
2116736Srrh if ((*s=next())==TAB || *s=='\n' || *s==LF)
2126736Srrh break;
2136736Srrh breakch= *s; /* save char for rtrav() */
2146736Srrh *s=0; /* got the number as ascii */
2156736Srrh if (nbf[0]=='-') return(-1); /* end of data */
2166736Srrh return(atoi(nbf)); /* convert it to integer */
2176736Srrh }
2186736Srrh
21959968Sbostic char *seekhere;
2206736Srrh
rdesc(sect)2216736Srrh rdesc(sect) /* read description-format msgs */
2226736Srrh int sect;
2236736Srrh { register char *s,*t;
2246736Srrh register int locc;
22559968Sbostic char *seekstart, *maystart, *adrstart;
2266736Srrh char *entry;
22759968Sbostic
22859968Sbostic seekhere = inptr; /* Where are we in virtual file?*/
2296736Srrh outsw=1; /* these msgs go into tmp file */
2306736Srrh for (oldloc= -1, seekstart=seekhere;;)
23159968Sbostic { maystart=inptr; /* maybe starting new entry */
2326736Srrh if ((locc=rnum())!=oldloc && oldloc>=0 /* finished msg */
2336736Srrh && ! (sect==5 && (locc==0 || locc>=100)))/* unless sect 5*/
2346736Srrh { switch(sect) /* now put it into right table */
2356736Srrh { case 1: /* long descriptions */
2366736Srrh ltext[oldloc].seekadr=seekhere;
2376736Srrh ltext[oldloc].txtlen=maystart-seekstart;
2386736Srrh break;
2396736Srrh case 2: /* short descriptions */
2406736Srrh stext[oldloc].seekadr=seekhere;
2416736Srrh stext[oldloc].txtlen=maystart-seekstart;
2426736Srrh break;
2436736Srrh case 5: /* object descriptions */
2446736Srrh ptext[oldloc].seekadr=seekhere;
2456736Srrh ptext[oldloc].txtlen=maystart-seekstart;
2466736Srrh break;
2476736Srrh case 6: /* random messages */
2486736Srrh if (oldloc>RTXSIZ)
2496736Srrh { printf("Too many random msgs\n");
2506736Srrh exit(0);
2516736Srrh }
2526736Srrh rtext[oldloc].seekadr=seekhere;
2536736Srrh rtext[oldloc].txtlen=maystart-seekstart;
2546736Srrh break;
2556736Srrh case 10: /* class messages */
2566736Srrh ctext[clsses].seekadr=seekhere;
2576736Srrh ctext[clsses].txtlen=maystart-seekstart;
2586736Srrh cval[clsses++]=oldloc;
2596736Srrh break;
2606736Srrh case 12: /* magic messages */
2616736Srrh if (oldloc>MAGSIZ)
2626736Srrh { printf("Too many magic msgs\n");
2636736Srrh exit(0);
2646736Srrh }
2656736Srrh mtext[oldloc].seekadr=seekhere;
2666736Srrh mtext[oldloc].txtlen=maystart-seekstart;
2676736Srrh break;
2686736Srrh default:
2696736Srrh printf("rdesc called with bad section\n");
2706736Srrh exit(0);
2716736Srrh }
2726736Srrh seekhere += maystart-seekstart;
2736736Srrh }
2746736Srrh if (locc<0)
2756736Srrh { outsw=0; /* turn off output */
2766736Srrh seekhere += 3; /* -1<delimiter> */
2776736Srrh return;
2786736Srrh }
2796736Srrh if (sect!=5 || (locc>0 && locc<100))
2806736Srrh { if (oldloc!=locc)/* starting a new message */
2816736Srrh seekstart=maystart;
2826736Srrh oldloc=locc;
2836736Srrh }
2846736Srrh FLUSHLF; /* scan the line */
2856736Srrh }
2866736Srrh }
2876736Srrh
2886736Srrh
rtrav()2896736Srrh rtrav() /* read travel table */
2906736Srrh { register int locc;
2916736Srrh register struct travlist *t;
2926736Srrh register char *s;
2936736Srrh char buf[12];
2946736Srrh int len,m,n,entries;
2956736Srrh for (oldloc= -1;;) /* get another line */
2966736Srrh { if ((locc=rnum())!=oldloc && oldloc>=0) /* end of entry */
2976736Srrh {
2986736Srrh t->next = 0; /* terminate the old entry */
2996736Srrh /* printf("%d:%d entries\n",oldloc,entries); */
3006736Srrh /* twrite(oldloc); */
3016736Srrh }
3026736Srrh if (locc== -1) return;
3036736Srrh if (locc!=oldloc) /* getting a new entry */
3046736Srrh { t=travel[locc]=(struct travlist *) malloc(sizeof (struct travlist));
3056736Srrh /* printf("New travel list for %d\n",locc); */
3066736Srrh entries=0;
3076736Srrh oldloc=locc;
3086736Srrh }
3096736Srrh for (s=buf;; *s++) /* get the newloc number /ASCII */
3106736Srrh if ((*s=next())==TAB || *s==LF) break;
3116736Srrh *s=0;
3126736Srrh len=length(buf)-1; /* quad long number handling */
3136736Srrh /* printf("Newloc: %s (%d chars)\n",buf,len); */
3146736Srrh if (len<4) /* no "m" conditions */
3156736Srrh { m=0;
3166736Srrh n=atoi(buf); /* newloc mod 1000 = newloc */
3176736Srrh }
3186736Srrh else /* a long integer */
3196736Srrh { n=atoi(buf+len-3);
3206736Srrh buf[len-3]=0; /* terminate newloc/1000 */
3216736Srrh m=atoi(buf);
3226736Srrh }
3236736Srrh while (breakch!=LF) /* only do one line at a time */
3246736Srrh { if (entries++) t=t->next=(struct travlist *) malloc(sizeof (struct travlist));
3256736Srrh t->tverb=rnum();/* get verb from the file */
3266736Srrh t->tloc=n; /* table entry mod 1000 */
3276736Srrh t->conditions=m;/* table entry / 1000 */
3286736Srrh /* printf("entry %d for %d\n",entries,locc); */
3296736Srrh }
3306736Srrh }
3316736Srrh }
3326736Srrh
33359968Sbostic #ifdef DEBUG
3346736Srrh
twrite(loq)3356736Srrh twrite(loq) /* travel options from this loc */
3366736Srrh int loq;
3376736Srrh { register struct travlist *t;
3386736Srrh printf("If");
3396736Srrh speak(<ext[loq]);
3406736Srrh printf("then\n");
3416736Srrh for (t=travel[loq]; t!=0; t=t->next)
3426736Srrh { printf("verb %d takes you to ",t->tverb);
3436736Srrh if (t->tloc<=300)
3446736Srrh speak(<ext[t->tloc]);
3456736Srrh else if (t->tloc<=500)
3466736Srrh printf("special code %d\n",t->tloc-300);
3476736Srrh else
3486736Srrh rspeak(t->tloc-500);
3496736Srrh printf("under conditions %d\n",t->conditions);
3506736Srrh }
3516736Srrh }
3526736Srrh
35359968Sbostic #endif DEBUG
3546736Srrh
rvoc()3556736Srrh rvoc()
3566736Srrh { register char *s; /* read the vocabulary */
3576736Srrh register int index;
3586736Srrh char buf[6];
3596736Srrh for (;;)
3606736Srrh { index=rnum();
3616736Srrh if (index<0) break;
3626736Srrh for (s=buf,*s=0;; s++) /* get the word */
3636736Srrh if ((*s=next())==TAB || *s=='\n' || *s==LF
3646736Srrh || *s==' ') break;
3656736Srrh /* terminate word with newline, LF, tab, blank */
3666736Srrh if (*s!='\n' && *s!=LF) FLUSHLF; /* can be comments */
3676736Srrh *s=0;
3686736Srrh /* printf("\"%s\"=%d\n",buf,index);*/
3696736Srrh vocab(buf,-2,index);
3706736Srrh }
3716736Srrh /* prht(); */
3726736Srrh }
3736736Srrh
3746736Srrh
rlocs()3756736Srrh rlocs() /* initial object locations */
3766736Srrh { for (;;)
3776736Srrh { if ((obj=rnum())<0) break;
3786736Srrh plac[obj]=rnum(); /* initial loc for this obj */
3796736Srrh if (breakch==TAB) /* there's another entry */
3806736Srrh fixd[obj]=rnum();
3816736Srrh else fixd[obj]=0;
3826736Srrh }
3836736Srrh }
3846736Srrh
rdflt()3856736Srrh rdflt() /* default verb messages */
3866736Srrh { for (;;)
3876736Srrh { if ((verb=rnum())<0) break;
3886736Srrh actspk[verb]=rnum();
3896736Srrh }
3906736Srrh }
3916736Srrh
rliq()3926736Srrh rliq() /* liquid assets &c: cond bits */
3936736Srrh { register int bitnum;
3946736Srrh for (;;) /* read new bit list */
3956736Srrh { if ((bitnum=rnum())<0) break;
3966736Srrh for (;;) /* read locs for bits */
3976736Srrh { cond[rnum()] |= setbit[bitnum];
3986736Srrh if (breakch==LF) break;
3996736Srrh }
4006736Srrh }
4016736Srrh }
4026736Srrh
rhints()4036736Srrh rhints()
4046736Srrh { register int hintnum,i;
4056736Srrh hntmax=0;
4066736Srrh for (;;)
4076736Srrh { if ((hintnum=rnum())<0) break;
4086736Srrh for (i=1; i<5; i++)
4096736Srrh hints[hintnum][i]=rnum();
4106736Srrh if (hintnum>hntmax) hntmax=hintnum;
4116736Srrh }
4126736Srrh }
4136736Srrh
4146736Srrh
rspeak(msg)4156736Srrh rspeak(msg)
4166736Srrh int msg;
4176736Srrh { if (msg!=0) speak(&rtext[msg]);
4186736Srrh }
4196736Srrh
4206736Srrh
mspeak(msg)4216736Srrh mspeak(msg)
4226736Srrh int msg;
4236736Srrh { if (msg!=0) speak(&mtext[msg]);
4246736Srrh }
4256736Srrh
4266736Srrh
42759968Sbostic speak(msg) /* read, decrypt, and print a message (not ptext) */
42859968Sbostic struct text *msg;/* msg is a pointer to seek address and length of mess */
4296736Srrh {
43059968Sbostic register char *s, nonfirst;
4316736Srrh
43259968Sbostic s = msg->seekadr;
4336736Srrh nonfirst=0;
43459968Sbostic while (s - msg->seekadr < msg->txtlen) /* read a line at a time */
4356736Srrh { tape=iotape; /* restart decryption tape */
43659968Sbostic while ((*s++ ^ *tape++) != TAB); /* read past loc num */
4376736Srrh /* assume tape is longer than location number */
4386736Srrh /* plus the lookahead put together */
43959968Sbostic if ((*s ^ *tape) == '>' &&
44059968Sbostic (*(s+1) ^ *(tape+1)) == '$' &&
44159968Sbostic (*(s+2) ^ *(tape+2)) == '<') break;
44259968Sbostic if (blklin && !nonfirst++) putchar('\n');
4436736Srrh do
44459968Sbostic { if (*tape == 0) tape = iotape;/* rewind decryp tape */
44559968Sbostic putchar(*s ^ *tape);
44659968Sbostic } while ((*s++ ^ *tape++) != LF); /* better end with LF */
4476736Srrh }
4486736Srrh }
4496736Srrh
4506736Srrh
pspeak(m,skip)45159968Sbostic pspeak(m,skip) /* read, decrypt an print a ptext message */
45259968Sbostic int m; /* msg is the number of all the p msgs for this place */
4536736Srrh int skip; /* assumes object 1 doesn't have prop 1, obj 2 no prop 2 &c*/
45459968Sbostic {
45559968Sbostic register char *s,nonfirst;
45659968Sbostic char *numst, save;
45759968Sbostic struct text *msg;
45859968Sbostic char *tbuf;
45959968Sbostic
46059968Sbostic msg = &ptext[m];
46159968Sbostic if ((tbuf=(char *) malloc(msg->txtlen + 1)) == 0) bug(108);
46259968Sbostic memcpy(tbuf, msg->seekadr, msg->txtlen + 1); /* Room to null */
46359968Sbostic s = tbuf;
46459968Sbostic
4656736Srrh nonfirst=0;
46659968Sbostic while (s - tbuf < msg->txtlen) /* read line at a time */
4676736Srrh { tape=iotape; /* restart decryption tape */
4686736Srrh for (numst=s; (*s^= *tape++)!=TAB; s++); /* get number */
46959968Sbostic
47059968Sbostic save = *s; /* Temporarily trash the string (cringe) */
47159968Sbostic *s++ = 0; /* decrypting number within the string */
47259968Sbostic
47359968Sbostic if (atoi(numst) != 100 * skip && skip >= 0)
4746736Srrh { while ((*s++^*tape++)!=LF) /* flush the line */
4756736Srrh if (*tape==0) tape=iotape;
4766736Srrh continue;
4776736Srrh }
4786736Srrh if ((*s^*tape)=='>' && (*(s+1)^*(tape+1))=='$' &&
4796736Srrh (*(s+2)^*(tape+2))=='<') break;
4806736Srrh if (blklin && ! nonfirst++) putchar('\n');
4816736Srrh do
4826736Srrh { if (*tape==0) tape=iotape;
4836736Srrh putchar(*s^*tape);
4846736Srrh } while ((*s++^*tape++)!=LF); /* better end with LF */
4856736Srrh if (skip<0) break;
4866736Srrh }
4876736Srrh free(tbuf);
4886736Srrh }
489