]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - games/adventure/io.c
Merge a bunch of cleanups from NetBSD.
[FreeBSD/FreeBSD.git] / games / adventure / io.c
1 /*-
2  * Copyright (c) 1991, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
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.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
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.
25  *
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
36  * SUCH DAMAGE.
37  */
38
39 #ifndef lint
40 static char sccsid[] = "@(#)io.c        8.1 (Berkeley) 5/31/93";
41 #endif /* not lint */
42
43 /*      Re-coding of advent in C: file i/o and user i/o                 */
44
45 #include "hdr.h"
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <err.h>
50
51
52 getin(wrd1,wrd2)                        /* get command from user        */
53 char **wrd1,**wrd2;                     /* no prompt, usually           */
54 {       register char *s;
55         static char wd1buf[MAXSTR],wd2buf[MAXSTR];
56         int first, numch;
57
58         *wrd1=wd1buf;                   /* return ptr to internal string*/
59         *wrd2=wd2buf;
60         wd2buf[0]=0;                    /* in case it isn't set here    */
61         for (s=wd1buf, first=1, numch=0;;)
62         {       if ((*s=getchar())>='A' && *s <='Z') *s = *s - ('A' -'a');
63                                         /* convert to upper case        */
64                 switch(*s)              /* start reading from user      */
65                 {   case '\n':
66                         *s=0;
67                         return;
68                     case ' ':
69                         if (s==wd1buf||s==wd2buf)  /* initial blank   */
70                                 continue;
71                         *s=0;
72                         if (first)      /* finished 1st wd; start 2nd   */
73                         {       first=numch=0;
74                                 s=wd2buf;
75                                 break;
76                         }
77                         else            /* finished 2nd word            */
78                         {       FLUSHLINE;
79                                 *s=0;
80                                 return;
81                         }
82                     case EOF:
83                         printf("user closed input stream, quitting...\n");
84                         exit(0);
85                     default:
86                         if (++numch>=MAXSTR)    /* string too long      */
87                         {       printf("Give me a break!!\n");
88                                 wd1buf[0]=wd2buf[0]=0;
89                                 FLUSHLINE;
90                                 return;
91                         }
92                         s++;
93                 }
94         }
95 }
96
97 yes(x,y,z)                              /* confirm with rspeak          */
98 int x,y,z;
99 {       register int result;
100         int ch;
101         for (;;)
102         {       rspeak(x);                     /* tell him what we want*/
103                 if ((ch=getchar())=='y')
104                         result=TRUE;
105                 else if (ch=='n') result=FALSE;
106                 else if (ch == EOF) {
107                         printf("user closed input stream, quitting...\n");
108                         exit(0);
109                 }
110                 FLUSHLINE;
111                 if (ch=='y'|| ch=='n') break;
112                 printf("Please answer the question.\n");
113         }
114         if (result==TRUE) rspeak(y);
115         if (result==FALSE) rspeak(z);
116         return(result);
117 }
118
119 yesm(x,y,z)                             /* confirm with mspeak          */
120 int x,y,z;
121 {       register int result;
122         int ch;
123         for (;;)
124         {       mspeak(x);                     /* tell him what we want*/
125                 if ((ch=getchar())=='y')
126                         result=TRUE;
127                 else if (ch=='n') result=FALSE;
128                 else if (ch == EOF) {
129                         printf("user closed input stream, quitting...\n");
130                         exit(0);
131                 }
132                 FLUSHLINE;
133                 if (ch=='y'|| ch=='n') break;
134                 printf("Please answer the question.\n");
135         }
136         if (result==TRUE) mspeak(y);
137         if (result==FALSE) mspeak(z);
138         return(result);
139 }
140
141 /* FILE *inbuf,*outbuf; */
142
143 char *inptr;                            /* Pointer into virtual disk    */
144
145 int outsw = 0;                          /* putting stuff to data file?  */
146
147 const char iotape[] = "Ax3F'\003tt$8h\315qer*h\017nGKrX\207:!l";
148 const char *tape = iotape;              /* pointer to encryption tape   */
149
150 next()                                  /* next virtual char, bump adr  */
151 {
152         int ch;
153
154         ch=(*inptr ^ random()) & 0xFF;  /* Decrypt input data           */
155         if (outsw)                      /* putting data in tmp file     */
156         {   if (*tape==0) tape=iotape;  /* rewind encryption tape       */
157             *inptr = ch ^ *tape++;      /* re-encrypt and replace value */
158         }
159         inptr++;
160         return(ch);
161 }
162
163 char breakch;                           /* tell which char ended rnum   */
164
165 rdata()                                 /* "read" data from virtual file*/
166 {       register int sect;
167         register char ch;
168
169         inptr = data_file;              /* Pointer to virtual data file */
170         srandom(SEED);                  /* which is lightly encrypted.  */
171
172         clsses=1;
173         for (;;)                        /* read data sections           */
174         {       sect=next()-'0';        /* 1st digit of section number  */
175 #ifdef VERBOSE
176                 printf("Section %c",sect+'0');
177 #endif
178                 if ((ch=next())!=LF)    /* is there a second digit?     */
179                 {
180                         FLUSHLF;
181 #ifdef VERBOSE
182                         putchar(ch);
183 #endif
184                         sect=10*sect+ch-'0';
185                 }
186 #ifdef VERBOSE
187                 putchar('\n');
188 #endif
189                 switch(sect)
190                 {   case 0:             /* finished reading database    */
191                         return;
192                     case 1:             /* long form descriptions       */
193                         rdesc(1);
194                         break;
195                     case 2:             /* short form descriptions      */
196                         rdesc(2);
197                         break;
198                     case 3:             /* travel table                 */
199                         rtrav();   break;
200                     case 4:             /* vocabulary                   */
201                         rvoc();
202                         break;
203                     case 5:             /* object descriptions          */
204                         rdesc(5);
205                         break;
206                     case 6:             /* arbitrary messages           */
207                         rdesc(6);
208                         break;
209                     case 7:             /* object locations             */
210                         rlocs();   break;
211                     case 8:             /* action defaults              */
212                         rdflt();   break;
213                     case 9:             /* liquid assets                */
214                         rliq();    break;
215                     case 10:            /* class messages               */
216                         rdesc(10);
217                         break;
218                     case 11:            /* hints                        */
219                         rhints();  break;
220                     case 12:            /* magic messages               */
221                         rdesc(12);
222                         break;
223                     default:
224                         printf("Invalid data section number: %d\n",sect);
225                         for (;;) putchar(next());
226                 }
227                 if (breakch!=LF)        /* routines return after "-1"   */
228                         FLUSHLF;
229         }
230 }
231
232 char nbf[12];
233
234
235 rnum()                                  /* read initial location num    */
236 {       register char *s;
237         tape = iotape;                  /* restart encryption tape      */
238         for (s=nbf,*s=0;; s++)
239                 if ((*s=next())==TAB || *s=='\n' || *s==LF)
240                         break;
241         breakch= *s;                    /* save char for rtrav()        */
242         *s=0;                           /* got the number as ascii      */
243         if (nbf[0]=='-') return(-1);    /* end of data                  */
244         return(atoi(nbf));              /* convert it to integer        */
245 }
246
247 char *seekhere;
248
249 rdesc(sect)                             /* read description-format msgs */
250 int sect;
251 {       register char *s,*t;
252         register int locc;
253         char *seekstart, *maystart, *adrstart;
254         char *entry;
255
256         seekhere = inptr;               /* Where are we in virtual file?*/
257         outsw=1;                        /* these msgs go into tmp file  */
258         for (oldloc= -1, seekstart=seekhere;;)
259         {       maystart=inptr;         /* maybe starting new entry     */
260                 if ((locc=rnum())!=oldloc && oldloc>=0  /* finished msg */
261                     && ! (sect==5 && (locc==0 || locc>=100)))/* unless sect 5*/
262                 {       switch(sect)    /* now put it into right table  */
263                         {   case 1:     /* long descriptions            */
264                                 ltext[oldloc].seekadr=seekhere;
265                                 ltext[oldloc].txtlen=maystart-seekstart;
266                                 break;
267                             case 2:     /* short descriptions           */
268                                 stext[oldloc].seekadr=seekhere;
269                                 stext[oldloc].txtlen=maystart-seekstart;
270                                 break;
271                             case 5:     /* object descriptions          */
272                                 ptext[oldloc].seekadr=seekhere;
273                                 ptext[oldloc].txtlen=maystart-seekstart;
274                                 break;
275                             case 6:     /* random messages              */
276                                 if (oldloc>RTXSIZ)
277                                 {       errx(1, "Too many random msgs");
278                                 }
279                                 rtext[oldloc].seekadr=seekhere;
280                                 rtext[oldloc].txtlen=maystart-seekstart;
281                                 break;
282                             case 10:    /* class messages               */
283                                 ctext[clsses].seekadr=seekhere;
284                                 ctext[clsses].txtlen=maystart-seekstart;
285                                 cval[clsses++]=oldloc;
286                                 break;
287                             case 12:    /* magic messages               */
288                                 if (oldloc>MAGSIZ)
289                                 {       errx(1, "Too many magic msgs");
290                                 }
291                                 mtext[oldloc].seekadr=seekhere;
292                                 mtext[oldloc].txtlen=maystart-seekstart;
293                                 break;
294                             default:
295                                 errx(1, "rdesc called with bad section");
296                         }
297                         seekhere += maystart-seekstart;
298                 }
299                 if (locc<0)
300                 {       outsw=0;        /* turn off output              */
301                         seekhere += 3;  /* -1<delimiter>                */
302                         return;
303                 }
304                 if (sect!=5 || (locc>0 && locc<100))
305                 {       if (oldloc!=locc)/* starting a new message       */
306                                 seekstart=maystart;
307                         oldloc=locc;
308                 }
309                 FLUSHLF;                /* scan the line                */
310         }
311 }
312
313
314 rtrav()                                 /* read travel table            */
315 {       register int locc;
316         register struct travlist *t;
317         register char *s;
318         char buf[12];
319         int len,m,n,entries;
320         for (oldloc= -1;;)              /* get another line             */
321         {       if ((locc=rnum())!=oldloc && oldloc>=0) /* end of entry */
322                 {
323                         t->next = 0;    /* terminate the old entry      */
324                 /*      printf("%d:%d entries\n",oldloc,entries);       */
325                 /*      twrite(oldloc);                                 */
326                 }
327                 if (locc== -1) return;
328                 if (locc!=oldloc)        /* getting a new entry         */
329                 {       t=travel[locc]=(struct travlist *) malloc(sizeof (struct travlist));
330                 /*      printf("New travel list for %d\n",locc);        */
331                         if (t == NULL)
332                                 errx(1, "Out of memory!");
333                         entries=0;
334                         oldloc=locc;
335                 }
336                 for (s=buf;; *s++)      /* get the newloc number /ASCII */
337                         if ((*s=next())==TAB || *s==LF) break;
338                 *s=0;
339                 len=strlen(buf);      /* quad long number handling    */
340         /*      printf("Newloc: %s (%d chars)\n",buf,len);              */
341                 if (len<4)              /* no "m" conditions            */
342                 {       m=0;
343                         n=atoi(buf);    /* newloc mod 1000 = newloc     */
344                 }
345                 else                    /* a long integer               */
346                 {       n=atoi(buf+len-3);
347                         buf[len-3]=0;   /* terminate newloc/1000        */
348                         m=atoi(buf);
349                 }
350                 while (breakch!=LF)     /* only do one line at a time   */
351                 {       if (entries++) {
352                                 t=t->next=(struct travlist *) malloc(sizeof (struct travlist));
353                                 if (t == NULL)
354                                         errx(1, "Out of memory!");
355                         }
356                         t->tverb=rnum();/* get verb from the file       */
357                         t->tloc=n;      /* table entry mod 1000         */
358                         t->conditions=m;/* table entry / 1000           */
359                 /*      printf("entry %d for %d\n",entries,locc);       */
360                 }
361         }
362 }
363
364 #ifdef DEBUG
365
366 twrite(loq)                             /* travel options from this loc */
367 int loq;
368 {       register struct travlist *t;
369         printf("If");
370         speak(&ltext[loq]);
371         printf("then\n");
372         for (t=travel[loq]; t!=0; t=t->next)
373         {       printf("verb %d takes you to ",t->tverb);
374                 if (t->tloc<=300)
375                         speak(&ltext[t->tloc]);
376                 else if (t->tloc<=500)
377                         printf("special code %d\n",t->tloc-300);
378                 else
379                         rspeak(t->tloc-500);
380                 printf("under conditions %d\n",t->conditions);
381         }
382 }
383
384 #endif DEBUG
385
386 rvoc()
387 {       register char *s;               /* read the vocabulary          */
388         register int index;
389         char buf[6];
390         for (;;)
391         {       index=rnum();
392                 if (index<0) break;
393                 for (s=buf,*s=0;; s++)  /* get the word                 */
394                         if ((*s=next())==TAB || *s=='\n' || *s==LF
395                                 || *s==' ') break;
396                         /* terminate word with newline, LF, tab, blank  */
397                 if (*s!='\n' && *s!=LF) FLUSHLF;  /* can be comments    */
398                 *s=0;
399         /*      printf("\"%s\"=%d\n",buf,index);*/
400                 vocab(buf,-2,index);
401         }
402 /*      prht(); */
403 }
404
405
406 rlocs()                                 /* initial object locations     */
407 {       for (;;)
408         {       if ((obj=rnum())<0) break;
409                 plac[obj]=rnum();       /* initial loc for this obj     */
410                 if (breakch==TAB)       /* there's another entry        */
411                         fixd[obj]=rnum();
412                 else    fixd[obj]=0;
413         }
414 }
415
416 rdflt()                                 /* default verb messages        */
417 {       for (;;)
418         {       if ((verb=rnum())<0) break;
419                 actspk[verb]=rnum();
420         }
421 }
422
423 rliq()                                  /* liquid assets &c: cond bits  */
424 {       register int bitnum;
425         for (;;)                        /* read new bit list            */
426         {       if ((bitnum=rnum())<0) break;
427                 for (;;)                /* read locs for bits           */
428                 {       cond[rnum()] |= setbit[bitnum];
429                         if (breakch==LF) break;
430                 }
431         }
432 }
433
434 rhints()
435 {       register int hintnum,i;
436         hntmax=0;
437         for (;;)
438         {       if ((hintnum=rnum())<0) break;
439                 for (i=1; i<5; i++)
440                         hints[hintnum][i]=rnum();
441                 if (hintnum>hntmax) hntmax=hintnum;
442         }
443 }
444
445
446 rspeak(msg)
447 int msg;
448 {       if (msg!=0) speak(&rtext[msg]);
449 }
450
451
452 mspeak(msg)
453 int msg;
454 {       if (msg!=0) speak(&mtext[msg]);
455 }
456
457
458 speak(msg)       /* read, decrypt, and print a message (not ptext)      */
459 const struct text *msg;/* msg is a pointer to seek address and length of mess */
460 {
461         register char *s, nonfirst;
462
463         s = msg->seekadr;
464         nonfirst=0;
465         while (s - msg->seekadr < msg->txtlen)  /* read a line at a time */
466         {       tape=iotape;            /* restart decryption tape      */
467                 while ((*s++ ^ *tape++) != TAB); /* read past loc num       */
468                 /* assume tape is longer than location number           */
469                 /*   plus the lookahead put together                    */
470                 if ((*s ^ *tape) == '>' &&
471                         (*(s+1) ^ *(tape+1)) == '$' &&
472                         (*(s+2) ^ *(tape+2)) == '<') break;
473                 if (blklin && !nonfirst++) putchar('\n');
474                 do
475                 {       if (*tape == 0) tape = iotape;/* rewind decryp tape */
476                         putchar(*s ^ *tape);
477                 } while ((*s++ ^ *tape++) != LF);   /* better end with LF   */
478         }
479 }
480
481
482 pspeak(m,skip) /* read, decrypt an print a ptext message              */
483 int m;         /* msg is the number of all the p msgs for this place  */
484 int skip;       /* assumes object 1 doesn't have prop 1, obj 2 no prop 2 &c*/
485 {
486         register char *s,nonfirst;
487         char *numst, save;
488         struct text *msg;
489         char *tbuf;
490
491         msg = &ptext[m];
492         if ((tbuf=(char *) malloc(msg->txtlen + 1)) == 0)
493                 errx(1, "Out of memory!");
494         memcpy(tbuf, msg->seekadr, msg->txtlen + 1);   /* Room to null */
495         s = tbuf;
496
497         nonfirst=0;
498         while (s - tbuf < msg->txtlen) /* read line at a time */
499         {       tape=iotape;            /* restart decryption tape      */
500                 for (numst=s; (*s^= *tape++)!=TAB; s++); /* get number  */
501
502                 save = *s; /* Temporarily trash the string (cringe) */
503                 *s++ = 0; /* decrypting number within the string          */
504
505                 if (atoi(numst) != 100 * skip && skip >= 0)
506                 {       while ((*s++^*tape++)!=LF) /* flush the line    */
507                                 if (*tape==0) tape=iotape;
508                         continue;
509                 }
510                 if ((*s^*tape)=='>' && (*(s+1)^*(tape+1))=='$' &&
511                         (*(s+2)^*(tape+2))=='<') break;
512                 if (blklin && ! nonfirst++) putchar('\n');
513                 do
514                 {       if (*tape==0) tape=iotape;
515                         putchar(*s^*tape);
516                 } while ((*s++^*tape++)!=LF);   /* better end with LF   */
517                 if (skip<0) break;
518         }
519         free(tbuf);
520 }