]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - games/adventure/io.c
This commit was generated by cvs2svn to compensate for changes in r61209,
[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 #if 0
41 static char sccsid[] = "@(#)io.c        8.1 (Berkeley) 5/31/93";
42 #endif
43 static const char rcsid[] =
44  "$FreeBSD$";
45 #endif /* not lint */
46
47 /*      Re-coding of advent in C: file i/o and user i/o                 */
48
49 #include "hdr.h"
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <err.h>
54
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);
64 #ifdef DEBUG
65 static void twrite (int);
66 #endif
67
68 void
69 getin(wrd1,wrd2)                        /* get command from user        */
70 char **wrd1,**wrd2;                     /* no prompt, usually           */
71 {       char *s;
72         static char wd1buf[MAXSTR],wd2buf[MAXSTR];
73         int first, numch;
74
75         *wrd1=wd1buf;                   /* return ptr to internal string*/
76         *wrd2=wd2buf;
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      */
82                 {   case '\n':
83                         *s=0;
84                         return;
85                     case ' ':
86                         if (s==wd1buf||s==wd2buf)  /* initial blank   */
87                                 continue;
88                         *s=0;
89                         if (first)      /* finished 1st wd; start 2nd   */
90                         {       first=numch=0;
91                                 s=wd2buf;
92                                 break;
93                         }
94                         else            /* finished 2nd word            */
95                         {       FLUSHLINE;
96                                 *s=0;
97                                 return;
98                         }
99                     case EOF:
100                         printf("user closed input stream, quitting...\n");
101                         exit(0);
102                     default:
103                         if (++numch>=MAXSTR)    /* string too long      */
104                         {       printf("Give me a break!!\n");
105                                 wd1buf[0]=wd2buf[0]=0;
106                                 FLUSHLINE;
107                                 return;
108                         }
109                         s++;
110                 }
111         }
112 }
113
114 int
115 yes(x,y,z)                              /* confirm with rspeak          */
116 int x,y,z;
117 {       int result;
118         int ch;
119         result = FALSE;
120         for (;;)
121         {       rspeak(x);                     /* tell him what we want*/
122                 if ((ch=getchar())=='y')
123                         result=TRUE;
124                 else if (ch=='n') result=FALSE;
125                 else if (ch == EOF) {
126                         printf("user closed input stream, quitting...\n");
127                         exit(0);
128                 }
129                 FLUSHLINE;
130                 if (ch=='y'|| ch=='n') break;
131                 printf("Please answer the question.\n");
132         }
133         if (result==TRUE) rspeak(y);
134         if (result==FALSE) rspeak(z);
135         return(result);
136 }
137
138 int
139 yesm(x,y,z)                             /* confirm with mspeak          */
140 int x,y,z;
141 {       int result;
142         int ch;
143         result = FALSE;
144         for (;;)
145         {       mspeak(x);                     /* tell him what we want*/
146                 if ((ch=getchar())=='y')
147                         result=TRUE;
148                 else if (ch=='n') result=FALSE;
149                 else if (ch == EOF) {
150                         printf("user closed input stream, quitting...\n");
151                         exit(0);
152                 }
153                 FLUSHLINE;
154                 if (ch=='y'|| ch=='n') break;
155                 printf("Please answer the question.\n");
156         }
157         if (result==TRUE) mspeak(y);
158         if (result==FALSE) mspeak(z);
159         return(result);
160 }
161
162 /* FILE *inbuf,*outbuf; */
163
164 char *inptr;                            /* Pointer into virtual disk    */
165
166 int outsw = 0;                          /* putting stuff to data file?  */
167
168 const char iotape[] = "Ax3F'\003tt$8h\315qer*h\017nGKrX\207:!l";
169 const char *tape = iotape;              /* pointer to encryption tape   */
170
171 static int
172 next()                                  /* next virtual char, bump adr  */
173 {
174         int ch;
175
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 */
180         }
181         inptr++;
182         return(ch);
183 }
184
185 char breakch;                           /* tell which char ended rnum   */
186
187 void
188 rdata()                                 /* "read" data from virtual file*/
189 {       int sect;
190         char ch;
191
192         inptr = data_file;              /* Pointer to virtual data file */
193         srandom(SEED);                  /* which is lightly encrypted.  */
194
195         clsses=1;
196         for (;;)                        /* read data sections           */
197         {       sect=next()-'0';        /* 1st digit of section number  */
198 #ifdef VERBOSE
199                 printf("Section %c",sect+'0');
200 #endif
201                 if ((ch=next())!=LF)    /* is there a second digit?     */
202                 {
203                         FLUSHLF;
204 #ifdef VERBOSE
205                         putchar(ch);
206 #endif
207                         sect=10*sect+ch-'0';
208                 }
209 #ifdef VERBOSE
210                 putchar('\n');
211 #endif
212                 switch(sect)
213                 {   case 0:             /* finished reading database    */
214                         return;
215                     case 1:             /* long form descriptions       */
216                         rdesc(1);
217                         break;
218                     case 2:             /* short form descriptions      */
219                         rdesc(2);
220                         break;
221                     case 3:             /* travel table                 */
222                         rtrav();   break;
223                     case 4:             /* vocabulary                   */
224                         rvoc();
225                         break;
226                     case 5:             /* object descriptions          */
227                         rdesc(5);
228                         break;
229                     case 6:             /* arbitrary messages           */
230                         rdesc(6);
231                         break;
232                     case 7:             /* object locations             */
233                         rlocs();   break;
234                     case 8:             /* action defaults              */
235                         rdflt();   break;
236                     case 9:             /* liquid assets                */
237                         rliq();    break;
238                     case 10:            /* class messages               */
239                         rdesc(10);
240                         break;
241                     case 11:            /* hints                        */
242                         rhints();  break;
243                     case 12:            /* magic messages               */
244                         rdesc(12);
245                         break;
246                     default:
247                         printf("Invalid data section number: %d\n",sect);
248                         for (;;) putchar(next());
249                 }
250                 if (breakch!=LF)        /* routines return after "-1"   */
251                         FLUSHLF;
252         }
253 }
254
255 char nbf[12];
256
257
258 static int
259 rnum()                                  /* read initial location num    */
260 {       char *s;
261         tape = iotape;                  /* restart encryption tape      */
262         for (s=nbf,*s=0;; s++)
263                 if ((*s=next())==TAB || *s=='\n' || *s==LF)
264                         break;
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        */
269 }
270
271 char *seekhere;
272
273 static 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                                 }
303                                 rtext[oldloc].seekadr=seekhere;
304                                 rtext[oldloc].txtlen=maystart-seekstart;
305                                 break;
306                             case 10:    /* class messages               */
307                                 ctext[clsses].seekadr=seekhere;
308                                 ctext[clsses].txtlen=maystart-seekstart;
309                                 cval[clsses++]=oldloc;
310                                 break;
311                             case 12:    /* magic messages               */
312                                 if (oldloc>MAGSIZ)
313                                 {       errx(1, "Too many magic msgs");
314                                 }
315                                 mtext[oldloc].seekadr=seekhere;
316                                 mtext[oldloc].txtlen=maystart-seekstart;
317                                 break;
318                             default:
319                                 errx(1, "rdesc called with bad section");
320                         }
321                         seekhere += maystart-seekstart;
322                 }
323                 if (locc<0)
324                 {       outsw=0;        /* turn off output              */
325                         seekhere += 3;  /* -1<delimiter>                */
326                         return;
327                 }
328                 if (sect!=5 || (locc>0 && locc<100))
329                 {       if (oldloc!=locc)/* starting a new message       */
330                                 seekstart=maystart;
331                         oldloc=locc;
332                 }
333                 FLUSHLF;                /* scan the line                */
334         }
335 }
336
337
338 static void
339 rtrav()                                 /* read travel table            */
340 {       int locc;
341         struct travlist *t;
342         char *s;
343         char buf[12];
344         int len,m,n,entries;
345         entries = 0;
346         t = NULL;
347         for (oldloc= -1;;)              /* get another line             */
348         {       if ((locc=rnum())!=oldloc && oldloc>=0) /* end of entry */
349                 {
350                         t->next = 0;    /* terminate the old entry      */
351 #if DEBUG
352                         printf("%d:%d entries\n",oldloc,entries);
353                         twrite(oldloc);
354 #endif
355                 }
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);        */
360                         if (t == NULL)
361                                 errx(1, "Out of memory!");
362                         entries=0;
363                         oldloc=locc;
364                 }
365                 s = buf;
366                 for (;; s++)      /* get the newloc number /ASCII */
367                         if ((*s=next())==TAB || *s==LF) break;
368                 *s=0;
369                 len=strlen(buf);      /* quad long number handling    */
370         /*      printf("Newloc: %s (%d chars)\n",buf,len);              */
371                 if (len<4)              /* no "m" conditions            */
372                 {       m=0;
373                         n=atoi(buf);    /* newloc mod 1000 = newloc     */
374                 }
375                 else                    /* a long integer               */
376                 {       n=atoi(buf+len-3);
377                         buf[len-3]=0;   /* terminate newloc/1000        */
378                         m=atoi(buf);
379                 }
380                 while (breakch!=LF)     /* only do one line at a time   */
381                 {       if (entries++) {
382                                 t=t->next=(struct travlist *) malloc(sizeof (struct travlist));
383                                 if (t == NULL)
384                                         errx(1, "Out of memory!");
385                         }
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);       */
390                 }
391         }
392 }
393
394 #ifdef DEBUG
395
396 static void
397 twrite(loq)                             /* travel options from this loc */
398 int loq;
399 {       struct travlist *t;
400         printf("If");
401         speak(&ltext[loq]);
402         printf("then\n");
403         for (t=travel[loq]; t!=0; t=t->next)
404         {       printf("verb %d takes you to ",t->tverb);
405                 if (t->tloc<=300)
406                         speak(&ltext[t->tloc]);
407                 else if (t->tloc<=500)
408                         printf("special code %d\n",t->tloc-300);
409                 else
410                         rspeak(t->tloc-500);
411                 printf("under conditions %d\n",t->conditions);
412         }
413 }
414
415 #endif DEBUG
416
417 static void
418 rvoc()
419 {       char *s;               /* read the vocabulary          */
420         int index;
421         char buf[6];
422         for (;;)
423         {       index=rnum();
424                 if (index<0) break;
425                 for (s=buf,*s=0;; s++)  /* get the word                 */
426                         if ((*s=next())==TAB || *s=='\n' || *s==LF
427                                 || *s==' ') break;
428                         /* terminate word with newline, LF, tab, blank  */
429                 if (*s!='\n' && *s!=LF) FLUSHLF;  /* can be comments    */
430                 *s=0;
431         /*      printf("\"%s\"=%d\n",buf,index);*/
432                 vocab(buf,-2,index);
433         }
434 }
435
436
437 static void
438 rlocs()                                 /* initial object locations     */
439 {       for (;;)
440         {       if ((obj=rnum())<0) break;
441                 plac[obj]=rnum();       /* initial loc for this obj     */
442                 if (breakch==TAB)       /* there's another entry        */
443                         fixd[obj]=rnum();
444                 else    fixd[obj]=0;
445         }
446 }
447
448 static void
449 rdflt()                                 /* default verb messages        */
450 {       for (;;)
451         {       if ((verb=rnum())<0) break;
452                 actspk[verb]=rnum();
453         }
454 }
455
456 static void
457 rliq()                                  /* liquid assets &c: cond bits  */
458 {       int bitnum;
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;
464                 }
465         }
466 }
467
468 static void
469 rhints()
470 {       int hintnum,i;
471         hntmax=0;
472         for (;;)
473         {       if ((hintnum=rnum())<0) break;
474                 for (i=1; i<5; i++)
475                         hints[hintnum][i]=rnum();
476                 if (hintnum>hntmax) hntmax=hintnum;
477         }
478 }
479
480
481 void
482 rspeak(msg)
483 int msg;
484 {       if (msg!=0) speak(&rtext[msg]);
485 }
486
487
488 void
489 mspeak(msg)
490 int msg;
491 {       if (msg!=0) speak(&mtext[msg]);
492 }
493
494
495 void
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 */
498 {
499         char *s, nonfirst;
500
501         s = msg->seekadr;
502         nonfirst=0;
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');
512                 do
513                 {       if (*tape == 0) tape = iotape;/* rewind decryp tape */
514                         putchar(*s ^ *tape);
515                 } while ((*s++ ^ *tape++) != LF);   /* better end with LF   */
516         }
517 }
518
519
520 void
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*/
524 {
525         char *s,nonfirst;
526         char *numst, save;
527         struct text *msg;
528         char *tbuf;
529
530         msg = &ptext[m];
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 */
534         s = tbuf;
535
536         nonfirst=0;
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  */
540
541                 save = *s; /* Temporarily trash the string (cringe) */
542                 *s++ = 0; /* decrypting number within the string          */
543
544                 if (atoi(numst) != 100 * skip && skip >= 0)
545                 {       while ((*s++^*tape++)!=LF) /* flush the line    */
546                                 if (*tape==0) tape=iotape;
547                         continue;
548                 }
549                 if ((*s^*tape)=='>' && (*(s+1)^*(tape+1))=='$' &&
550                         (*(s+2)^*(tape+2))=='<') break;
551                 if (blklin && ! nonfirst++) putchar('\n');
552                 do
553                 {       if (*tape==0) tape=iotape;
554                         putchar(*s^*tape);
555                 } while ((*s++^*tape++)!=LF);   /* better end with LF   */
556                 if (skip<0) break;
557         }
558         free(tbuf);
559 }