2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
5 * The game adventure was originally written in Fortran by Will Crowther
6 * and Don Woods. It was later translated to C and enhanced by Jim
7 * Gillogly. This code is derived from software contributed to Berkeley
8 * by Jim Gillogly at The Rand Corporation.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 static char sccsid[] = "@(#)io.c 8.1 (Berkeley) 5/31/93";
43 static const char rcsid[] =
47 /* Re-coding of advent in C: file i/o and user i/o */
55 static int next (void);
56 static int rnum (void);
57 static void rdesc (int);
58 static void rdflt (void);
59 static void rhints (void);
60 static void rliq (void);
61 static void rlocs (void);
62 static void rtrav (void);
63 static void rvoc (void);
65 static void twrite (int);
69 getin(wrd1,wrd2) /* get command from user */
70 char **wrd1,**wrd2; /* no prompt, usually */
72 static char wd1buf[MAXSTR],wd2buf[MAXSTR];
75 *wrd1=wd1buf; /* return ptr to internal string*/
77 wd2buf[0]=0; /* in case it isn't set here */
78 for (s=wd1buf, first=1, numch=0;;)
79 { if ((*s=getchar())>='A' && *s <='Z') *s = *s - ('A' -'a');
80 /* convert to upper case */
81 switch(*s) /* start reading from user */
86 if (s==wd1buf||s==wd2buf) /* initial blank */
89 if (first) /* finished 1st wd; start 2nd */
94 else /* finished 2nd word */
100 printf("user closed input stream, quitting...\n");
103 if (++numch>=MAXSTR) /* string too long */
104 { printf("Give me a break!!\n");
105 wd1buf[0]=wd2buf[0]=0;
115 yes(x,y,z) /* confirm with rspeak */
121 { rspeak(x); /* tell him what we want*/
122 if ((ch=getchar())=='y')
124 else if (ch=='n') result=FALSE;
125 else if (ch == EOF) {
126 printf("user closed input stream, quitting...\n");
130 if (ch=='y'|| ch=='n') break;
131 printf("Please answer the question.\n");
133 if (result==TRUE) rspeak(y);
134 if (result==FALSE) rspeak(z);
139 yesm(x,y,z) /* confirm with mspeak */
145 { mspeak(x); /* tell him what we want*/
146 if ((ch=getchar())=='y')
148 else if (ch=='n') result=FALSE;
149 else if (ch == EOF) {
150 printf("user closed input stream, quitting...\n");
154 if (ch=='y'|| ch=='n') break;
155 printf("Please answer the question.\n");
157 if (result==TRUE) mspeak(y);
158 if (result==FALSE) mspeak(z);
162 /* FILE *inbuf,*outbuf; */
164 char *inptr; /* Pointer into virtual disk */
166 int outsw = 0; /* putting stuff to data file? */
168 const char iotape[] = "Ax3F'\003tt$8h\315qer*h\017nGKrX\207:!l";
169 const char *tape = iotape; /* pointer to encryption tape */
172 next() /* next virtual char, bump adr */
176 ch=(*inptr ^ random()) & 0xFF; /* Decrypt input data */
177 if (outsw) /* putting data in tmp file */
178 { if (*tape==0) tape=iotape; /* rewind encryption tape */
179 *inptr = ch ^ *tape++; /* re-encrypt and replace value */
185 char breakch; /* tell which char ended rnum */
188 rdata() /* "read" data from virtual file*/
192 inptr = data_file; /* Pointer to virtual data file */
193 srandom(SEED); /* which is lightly encrypted. */
196 for (;;) /* read data sections */
197 { sect=next()-'0'; /* 1st digit of section number */
199 printf("Section %c",sect+'0');
201 if ((ch=next())!=LF) /* is there a second digit? */
213 { case 0: /* finished reading database */
215 case 1: /* long form descriptions */
218 case 2: /* short form descriptions */
221 case 3: /* travel table */
223 case 4: /* vocabulary */
226 case 5: /* object descriptions */
229 case 6: /* arbitrary messages */
232 case 7: /* object locations */
234 case 8: /* action defaults */
236 case 9: /* liquid assets */
238 case 10: /* class messages */
243 case 12: /* magic messages */
247 printf("Invalid data section number: %d\n",sect);
248 for (;;) putchar(next());
250 if (breakch!=LF) /* routines return after "-1" */
259 rnum() /* read initial location num */
261 tape = iotape; /* restart encryption tape */
262 for (s=nbf,*s=0;; s++)
263 if ((*s=next())==TAB || *s=='\n' || *s==LF)
265 breakch= *s; /* save char for rtrav() */
266 *s=0; /* got the number as ascii */
267 if (nbf[0]=='-') return(-1); /* end of data */
268 return(atoi(nbf)); /* convert it to integer */
274 rdesc(sect) /* read description-format msgs */
278 char *seekstart, *maystart;
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;
291 case 2: /* short descriptions */
292 stext[oldloc].seekadr=seekhere;
293 stext[oldloc].txtlen=maystart-seekstart;
295 case 5: /* object descriptions */
296 ptext[oldloc].seekadr=seekhere;
297 ptext[oldloc].txtlen=maystart-seekstart;
299 case 6: /* random messages */
301 { errx(1, "Too many random msgs");
303 rtext[oldloc].seekadr=seekhere;
304 rtext[oldloc].txtlen=maystart-seekstart;
306 case 10: /* class messages */
307 ctext[clsses].seekadr=seekhere;
308 ctext[clsses].txtlen=maystart-seekstart;
309 cval[clsses++]=oldloc;
311 case 12: /* magic messages */
313 { errx(1, "Too many magic msgs");
315 mtext[oldloc].seekadr=seekhere;
316 mtext[oldloc].txtlen=maystart-seekstart;
319 errx(1, "rdesc called with bad section");
321 seekhere += maystart-seekstart;
324 { outsw=0; /* turn off output */
325 seekhere += 3; /* -1<delimiter> */
328 if (sect!=5 || (locc>0 && locc<100))
329 { if (oldloc!=locc)/* starting a new message */
333 FLUSHLF; /* scan the line */
339 rtrav() /* read travel table */
347 for (oldloc= -1;;) /* get another line */
348 { if ((locc=rnum())!=oldloc && oldloc>=0) /* end of entry */
350 t->next = 0; /* terminate the old entry */
352 printf("%d:%d entries\n",oldloc,entries);
356 if (locc== -1) return;
357 if (locc!=oldloc) /* getting a new entry */
358 { t=travel[locc]=(struct travlist *) malloc(sizeof (struct travlist));
359 /* printf("New travel list for %d\n",locc); */
361 errx(1, "Out of memory!");
366 for (;; s++) /* get the newloc number /ASCII */
367 if ((*s=next())==TAB || *s==LF) break;
369 len=strlen(buf); /* quad long number handling */
370 /* printf("Newloc: %s (%d chars)\n",buf,len); */
371 if (len<4) /* no "m" conditions */
373 n=atoi(buf); /* newloc mod 1000 = newloc */
375 else /* a long integer */
377 buf[len-3]=0; /* terminate newloc/1000 */
380 while (breakch!=LF) /* only do one line at a time */
382 t=t->next=(struct travlist *) malloc(sizeof (struct travlist));
384 errx(1, "Out of memory!");
386 t->tverb=rnum();/* get verb from the file */
387 t->tloc=n; /* table entry mod 1000 */
388 t->conditions=m;/* table entry / 1000 */
389 /* printf("entry %d for %d\n",entries,locc); */
397 twrite(loq) /* travel options from this loc */
399 { struct travlist *t;
403 for (t=travel[loq]; t!=0; t=t->next)
404 { printf("verb %d takes you to ",t->tverb);
406 speak(<ext[t->tloc]);
407 else if (t->tloc<=500)
408 printf("special code %d\n",t->tloc-300);
411 printf("under conditions %d\n",t->conditions);
419 { char *s; /* read the vocabulary */
425 for (s=buf,*s=0;; s++) /* get the word */
426 if ((*s=next())==TAB || *s=='\n' || *s==LF
428 /* terminate word with newline, LF, tab, blank */
429 if (*s!='\n' && *s!=LF) FLUSHLF; /* can be comments */
431 /* printf("\"%s\"=%d\n",buf,index);*/
438 rlocs() /* initial object locations */
440 { if ((obj=rnum())<0) break;
441 plac[obj]=rnum(); /* initial loc for this obj */
442 if (breakch==TAB) /* there's another entry */
449 rdflt() /* default verb messages */
451 { if ((verb=rnum())<0) break;
457 rliq() /* liquid assets &c: cond bits */
459 for (;;) /* read new bit list */
460 { if ((bitnum=rnum())<0) break;
461 for (;;) /* read locs for bits */
462 { cond[rnum()] |= setbit[bitnum];
463 if (breakch==LF) break;
473 { if ((hintnum=rnum())<0) break;
475 hints[hintnum][i]=rnum();
476 if (hintnum>hntmax) hntmax=hintnum;
484 { if (msg!=0) speak(&rtext[msg]);
491 { if (msg!=0) speak(&mtext[msg]);
496 speak(msg) /* read, decrypt, and print a message (not ptext) */
497 const struct text *msg;/* msg is a pointer to seek address and length of mess */
503 while (s - msg->seekadr < msg->txtlen) /* read a line at a time */
504 { tape=iotape; /* restart decryption tape */
505 while ((*s++ ^ *tape++) != TAB); /* read past loc num */
506 /* assume tape is longer than location number */
507 /* plus the lookahead put together */
508 if ((*s ^ *tape) == '>' &&
509 (*(s+1) ^ *(tape+1)) == '$' &&
510 (*(s+2) ^ *(tape+2)) == '<') break;
511 if (blklin && !nonfirst++) putchar('\n');
513 { if (*tape == 0) tape = iotape;/* rewind decryp tape */
515 } while ((*s++ ^ *tape++) != LF); /* better end with LF */
521 pspeak(m,skip) /* read, decrypt an print a ptext message */
522 int m; /* msg is the number of all the p msgs for this place */
523 int skip; /* assumes object 1 doesn't have prop 1, obj 2 no prop 2 &c*/
531 if ((tbuf=(char *) malloc(msg->txtlen + 1)) == 0)
532 errx(1, "Out of memory!");
533 memcpy(tbuf, msg->seekadr, msg->txtlen + 1); /* Room to null */
537 while (s - tbuf < msg->txtlen) /* read line at a time */
538 { tape=iotape; /* restart decryption tape */
539 for (numst=s; (*s^= *tape++)!=TAB; s++); /* get number */
541 save = *s; /* Temporarily trash the string (cringe) */
542 *s++ = 0; /* decrypting number within the string */
544 if (atoi(numst) != 100 * skip && skip >= 0)
545 { while ((*s++^*tape++)!=LF) /* flush the line */
546 if (*tape==0) tape=iotape;
549 if ((*s^*tape)=='>' && (*(s+1)^*(tape+1))=='$' &&
550 (*(s+2)^*(tape+2))=='<') break;
551 if (blklin && ! nonfirst++) putchar('\n');
553 { if (*tape==0) tape=iotape;
555 } while ((*s++^*tape++)!=LF); /* better end with LF */