147851Sbostic /*- 2*59968Sbostic * Copyright (c) 1991, 1993 The Regents of the University of California. 347851Sbostic * All rights reserved. 447851Sbostic * 5*59968Sbostic * The game adventure was originally written in Fortran by Will Crowther 6*59968Sbostic * and Don Woods. It was later translated to C and enhanced by Jim 7*59968Sbostic * Gillogly. This code is derived from software contributed to Berkeley 8*59968Sbostic * by Jim Gillogly at The Rand Corporation. 947851Sbostic * 1047851Sbostic * %sccs.include.redist.c% 1147851Sbostic */ 1247851Sbostic 1347851Sbostic #ifndef lint 14*59968Sbostic static char sccsid[] = "@(#)io.c 5.2 (Berkeley) 05/12/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 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 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 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 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 113*59968Sbostic /* FILE *inbuf,*outbuf; */ 1146736Srrh 115*59968Sbostic char *inptr; /* Pointer into virtual disk */ 116*59968Sbostic 1176736Srrh int outsw = 0; /* putting stuff to data file? */ 1186736Srrh 119*59968Sbostic char iotape[] = "Ax3F'\003tt$8h\315qer*h\017nGKrX\207:!l"; 1206736Srrh char *tape = iotape; /* pointer to encryption tape */ 1216736Srrh 122*59968Sbostic next() /* next virtual char, bump adr */ 123*59968Sbostic { 124*59968Sbostic int ch; 125*59968Sbostic 126*59968Sbostic ch=(*inptr ^ random()) & 0xFF; /* Decrypt input data */ 1276736Srrh if (outsw) /* putting data in tmp file */ 128*59968Sbostic { if (*tape==0) tape=iotape; /* rewind encryption tape */ 129*59968Sbostic *inptr = ch ^ *tape++; /* re-encrypt and replace value */ 1306736Srrh } 131*59968Sbostic inptr++; 1326736Srrh return(ch); 1336736Srrh } 1346736Srrh 1356736Srrh char breakch; /* tell which char ended rnum */ 1366736Srrh 137*59968Sbostic rdata() /* "read" data from virtual file*/ 1386736Srrh { register int sect; 1396736Srrh register char ch; 140*59968Sbostic 141*59968Sbostic inptr = data_file; /* Pointer to virtual data file */ 142*59968Sbostic srandom(SEED); /* which is lightly encrypted. */ 143*59968Sbostic 144*59968Sbostic clsses=1; 1456736Srrh for (;;) /* read data sections */ 1466736Srrh { sect=next()-'0'; /* 1st digit of section number */ 147*59968Sbostic #ifdef VERBOSE 1486736Srrh printf("Section %c",sect+'0'); 149*59968Sbostic #endif 1506736Srrh if ((ch=next())!=LF) /* is there a second digit? */ 151*59968Sbostic { 152*59968Sbostic FLUSHLF; 153*59968Sbostic #ifdef VERBOSE 1546736Srrh putchar(ch); 155*59968Sbostic #endif 1566736Srrh sect=10*sect+ch-'0'; 1576736Srrh } 158*59968Sbostic #ifdef VERBOSE 1596736Srrh putchar('\n'); 160*59968Sbostic #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 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 219*59968Sbostic char *seekhere; 2206736Srrh 2216736Srrh rdesc(sect) /* read description-format msgs */ 2226736Srrh int sect; 2236736Srrh { register char *s,*t; 2246736Srrh register int locc; 225*59968Sbostic char *seekstart, *maystart, *adrstart; 2266736Srrh char *entry; 227*59968Sbostic 228*59968Sbostic seekhere = inptr; /* Where are we in virtual file?*/ 2296736Srrh outsw=1; /* these msgs go into tmp file */ 2306736Srrh for (oldloc= -1, seekstart=seekhere;;) 231*59968Sbostic { 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 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 333*59968Sbostic #ifdef DEBUG 3346736Srrh 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 353*59968Sbostic #endif DEBUG 3546736Srrh 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 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 3856736Srrh rdflt() /* default verb messages */ 3866736Srrh { for (;;) 3876736Srrh { if ((verb=rnum())<0) break; 3886736Srrh actspk[verb]=rnum(); 3896736Srrh } 3906736Srrh } 3916736Srrh 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 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 4156736Srrh rspeak(msg) 4166736Srrh int msg; 4176736Srrh { if (msg!=0) speak(&rtext[msg]); 4186736Srrh } 4196736Srrh 4206736Srrh 4216736Srrh mspeak(msg) 4226736Srrh int msg; 4236736Srrh { if (msg!=0) speak(&mtext[msg]); 4246736Srrh } 4256736Srrh 4266736Srrh 427*59968Sbostic speak(msg) /* read, decrypt, and print a message (not ptext) */ 428*59968Sbostic struct text *msg;/* msg is a pointer to seek address and length of mess */ 4296736Srrh { 430*59968Sbostic register char *s, nonfirst; 4316736Srrh 432*59968Sbostic s = msg->seekadr; 4336736Srrh nonfirst=0; 434*59968Sbostic while (s - msg->seekadr < msg->txtlen) /* read a line at a time */ 4356736Srrh { tape=iotape; /* restart decryption tape */ 436*59968Sbostic while ((*s++ ^ *tape++) != TAB); /* read past loc num */ 4376736Srrh /* assume tape is longer than location number */ 4386736Srrh /* plus the lookahead put together */ 439*59968Sbostic if ((*s ^ *tape) == '>' && 440*59968Sbostic (*(s+1) ^ *(tape+1)) == '$' && 441*59968Sbostic (*(s+2) ^ *(tape+2)) == '<') break; 442*59968Sbostic if (blklin && !nonfirst++) putchar('\n'); 4436736Srrh do 444*59968Sbostic { if (*tape == 0) tape = iotape;/* rewind decryp tape */ 445*59968Sbostic putchar(*s ^ *tape); 446*59968Sbostic } while ((*s++ ^ *tape++) != LF); /* better end with LF */ 4476736Srrh } 4486736Srrh } 4496736Srrh 4506736Srrh 451*59968Sbostic pspeak(m,skip) /* read, decrypt an print a ptext message */ 452*59968Sbostic 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*/ 454*59968Sbostic { 455*59968Sbostic register char *s,nonfirst; 456*59968Sbostic char *numst, save; 457*59968Sbostic struct text *msg; 458*59968Sbostic char *tbuf; 459*59968Sbostic 460*59968Sbostic msg = &ptext[m]; 461*59968Sbostic if ((tbuf=(char *) malloc(msg->txtlen + 1)) == 0) bug(108); 462*59968Sbostic memcpy(tbuf, msg->seekadr, msg->txtlen + 1); /* Room to null */ 463*59968Sbostic s = tbuf; 464*59968Sbostic 4656736Srrh nonfirst=0; 466*59968Sbostic 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 */ 469*59968Sbostic 470*59968Sbostic save = *s; /* Temporarily trash the string (cringe) */ 471*59968Sbostic *s++ = 0; /* decrypting number within the string */ 472*59968Sbostic 473*59968Sbostic 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