io.c revision 1.2 1 /* $NetBSD: io.c,v 1.2 1995/03/21 12:05:05 cgd Exp $ */
2
3 /*-
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * The game adventure was originally written in Fortran by Will Crowther
8 * and Don Woods. It was later translated to C and enhanced by Jim
9 * Gillogly. This code is derived from software contributed to Berkeley
10 * by Jim Gillogly at The Rand Corporation.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 */
40
41 #ifndef lint
42 #if 0
43 static char sccsid[] = "@(#)io.c 8.1 (Berkeley) 5/31/93";
44 #else
45 static char rcsid[] = "$NetBSD: io.c,v 1.2 1995/03/21 12:05:05 cgd Exp $";
46 #endif
47 #endif /* not lint */
48
49 /* Re-coding of advent in C: file i/o and user i/o */
50
51 #include "hdr.h"
52 #include <stdio.h>
53
54
55 getin(wrd1,wrd2) /* get command from user */
56 char **wrd1,**wrd2; /* no prompt, usually */
57 { register char *s;
58 static char wd1buf[MAXSTR],wd2buf[MAXSTR];
59 int first, numch;
60
61 *wrd1=wd1buf; /* return ptr to internal string*/
62 *wrd2=wd2buf;
63 wd2buf[0]=0; /* in case it isn't set here */
64 for (s=wd1buf, first=1, numch=0;;)
65 { if ((*s=getchar())>='A' && *s <='Z') *s = *s - ('A' -'a');
66 /* convert to upper case */
67 switch(*s) /* start reading from user */
68 { case '\n':
69 *s=0;
70 return;
71 case ' ':
72 if (s==wd1buf||s==wd2buf) /* initial blank */
73 continue;
74 *s=0;
75 if (first) /* finished 1st wd; start 2nd */
76 { first=numch=0;
77 s=wd2buf;
78 break;
79 }
80 else /* finished 2nd word */
81 { FLUSHLINE;
82 *s=0;
83 return;
84 }
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
98 confirm(mesg) /* confirm irreversible action */
99 char *mesg;
100 { register int result;
101 printf("%s",mesg); /* tell him what he did */
102 if (getchar()=='y') /* was his first letter a 'y'? */
103 result=1;
104 else result=0;
105 FLUSHLINE;
106 return(result);
107 }
108
109 yes(x,y,z) /* confirm with rspeak */
110 int x,y,z;
111 { register int result;
112 register char ch;
113 for (;;)
114 { rspeak(x); /* tell him what we want*/
115 if ((ch=getchar())=='y')
116 result=TRUE;
117 else if (ch=='n') result=FALSE;
118 FLUSHLINE;
119 if (ch=='y'|| ch=='n') break;
120 printf("Please answer the question.\n");
121 }
122 if (result==TRUE) rspeak(y);
123 if (result==FALSE) rspeak(z);
124 return(result);
125 }
126
127 yesm(x,y,z) /* confirm with mspeak */
128 int x,y,z;
129 { register int result;
130 register char ch;
131 for (;;)
132 { mspeak(x); /* tell him what we want*/
133 if ((ch=getchar())=='y')
134 result=TRUE;
135 else if (ch=='n') result=FALSE;
136 FLUSHLINE;
137 if (ch=='y'|| ch=='n') break;
138 printf("Please answer the question.\n");
139 }
140 if (result==TRUE) mspeak(y);
141 if (result==FALSE) mspeak(z);
142 return(result);
143 }
144
145 /* FILE *inbuf,*outbuf; */
146
147 char *inptr; /* Pointer into virtual disk */
148
149 int outsw = 0; /* putting stuff to data file? */
150
151 char iotape[] = "Ax3F'\003tt$8h\315qer*h\017nGKrX\207:!l";
152 char *tape = iotape; /* pointer to encryption tape */
153
154 next() /* next virtual char, bump adr */
155 {
156 int ch;
157
158 ch=(*inptr ^ random()) & 0xFF; /* Decrypt input data */
159 if (outsw) /* putting data in tmp file */
160 { if (*tape==0) tape=iotape; /* rewind encryption tape */
161 *inptr = ch ^ *tape++; /* re-encrypt and replace value */
162 }
163 inptr++;
164 return(ch);
165 }
166
167 char breakch; /* tell which char ended rnum */
168
169 rdata() /* "read" data from virtual file*/
170 { register int sect;
171 register char ch;
172
173 inptr = data_file; /* Pointer to virtual data file */
174 srandom(SEED); /* which is lightly encrypted. */
175
176 clsses=1;
177 for (;;) /* read data sections */
178 { sect=next()-'0'; /* 1st digit of section number */
179 #ifdef VERBOSE
180 printf("Section %c",sect+'0');
181 #endif
182 if ((ch=next())!=LF) /* is there a second digit? */
183 {
184 FLUSHLF;
185 #ifdef VERBOSE
186 putchar(ch);
187 #endif
188 sect=10*sect+ch-'0';
189 }
190 #ifdef VERBOSE
191 putchar('\n');
192 #endif
193 switch(sect)
194 { case 0: /* finished reading database */
195 return;
196 case 1: /* long form descriptions */
197 rdesc(1);
198 break;
199 case 2: /* short form descriptions */
200 rdesc(2);
201 break;
202 case 3: /* travel table */
203 rtrav(); break;
204 case 4: /* vocabulary */
205 rvoc();
206 break;
207 case 5: /* object descriptions */
208 rdesc(5);
209 break;
210 case 6: /* arbitrary messages */
211 rdesc(6);
212 break;
213 case 7: /* object locations */
214 rlocs(); break;
215 case 8: /* action defaults */
216 rdflt(); break;
217 case 9: /* liquid assets */
218 rliq(); break;
219 case 10: /* class messages */
220 rdesc(10);
221 break;
222 case 11: /* hints */
223 rhints(); break;
224 case 12: /* magic messages */
225 rdesc(12);
226 break;
227 default:
228 printf("Invalid data section number: %d\n",sect);
229 for (;;) putchar(next());
230 }
231 if (breakch!=LF) /* routines return after "-1" */
232 FLUSHLF;
233 }
234 }
235
236 char nbf[12];
237
238
239 rnum() /* read initial location num */
240 { register char *s;
241 tape = iotape; /* restart encryption tape */
242 for (s=nbf,*s=0;; s++)
243 if ((*s=next())==TAB || *s=='\n' || *s==LF)
244 break;
245 breakch= *s; /* save char for rtrav() */
246 *s=0; /* got the number as ascii */
247 if (nbf[0]=='-') return(-1); /* end of data */
248 return(atoi(nbf)); /* convert it to integer */
249 }
250
251 char *seekhere;
252
253 rdesc(sect) /* read description-format msgs */
254 int sect;
255 { register char *s,*t;
256 register int locc;
257 char *seekstart, *maystart, *adrstart;
258 char *entry;
259
260 seekhere = inptr; /* Where are we in virtual file?*/
261 outsw=1; /* these msgs go into tmp file */
262 for (oldloc= -1, seekstart=seekhere;;)
263 { maystart=inptr; /* maybe starting new entry */
264 if ((locc=rnum())!=oldloc && oldloc>=0 /* finished msg */
265 && ! (sect==5 && (locc==0 || locc>=100)))/* unless sect 5*/
266 { switch(sect) /* now put it into right table */
267 { case 1: /* long descriptions */
268 ltext[oldloc].seekadr=seekhere;
269 ltext[oldloc].txtlen=maystart-seekstart;
270 break;
271 case 2: /* short descriptions */
272 stext[oldloc].seekadr=seekhere;
273 stext[oldloc].txtlen=maystart-seekstart;
274 break;
275 case 5: /* object descriptions */
276 ptext[oldloc].seekadr=seekhere;
277 ptext[oldloc].txtlen=maystart-seekstart;
278 break;
279 case 6: /* random messages */
280 if (oldloc>RTXSIZ)
281 { printf("Too many random msgs\n");
282 exit(0);
283 }
284 rtext[oldloc].seekadr=seekhere;
285 rtext[oldloc].txtlen=maystart-seekstart;
286 break;
287 case 10: /* class messages */
288 ctext[clsses].seekadr=seekhere;
289 ctext[clsses].txtlen=maystart-seekstart;
290 cval[clsses++]=oldloc;
291 break;
292 case 12: /* magic messages */
293 if (oldloc>MAGSIZ)
294 { printf("Too many magic msgs\n");
295 exit(0);
296 }
297 mtext[oldloc].seekadr=seekhere;
298 mtext[oldloc].txtlen=maystart-seekstart;
299 break;
300 default:
301 printf("rdesc called with bad section\n");
302 exit(0);
303 }
304 seekhere += maystart-seekstart;
305 }
306 if (locc<0)
307 { outsw=0; /* turn off output */
308 seekhere += 3; /* -1<delimiter> */
309 return;
310 }
311 if (sect!=5 || (locc>0 && locc<100))
312 { if (oldloc!=locc)/* starting a new message */
313 seekstart=maystart;
314 oldloc=locc;
315 }
316 FLUSHLF; /* scan the line */
317 }
318 }
319
320
321 rtrav() /* read travel table */
322 { register int locc;
323 register struct travlist *t;
324 register char *s;
325 char buf[12];
326 int len,m,n,entries;
327 for (oldloc= -1;;) /* get another line */
328 { if ((locc=rnum())!=oldloc && oldloc>=0) /* end of entry */
329 {
330 t->next = 0; /* terminate the old entry */
331 /* printf("%d:%d entries\n",oldloc,entries); */
332 /* twrite(oldloc); */
333 }
334 if (locc== -1) return;
335 if (locc!=oldloc) /* getting a new entry */
336 { t=travel[locc]=(struct travlist *) malloc(sizeof (struct travlist));
337 /* printf("New travel list for %d\n",locc); */
338 entries=0;
339 oldloc=locc;
340 }
341 for (s=buf;; *s++) /* get the newloc number /ASCII */
342 if ((*s=next())==TAB || *s==LF) break;
343 *s=0;
344 len=length(buf)-1; /* quad long number handling */
345 /* printf("Newloc: %s (%d chars)\n",buf,len); */
346 if (len<4) /* no "m" conditions */
347 { m=0;
348 n=atoi(buf); /* newloc mod 1000 = newloc */
349 }
350 else /* a long integer */
351 { n=atoi(buf+len-3);
352 buf[len-3]=0; /* terminate newloc/1000 */
353 m=atoi(buf);
354 }
355 while (breakch!=LF) /* only do one line at a time */
356 { if (entries++) t=t->next=(struct travlist *) malloc(sizeof (struct travlist));
357 t->tverb=rnum();/* get verb from the file */
358 t->tloc=n; /* table entry mod 1000 */
359 t->conditions=m;/* table entry / 1000 */
360 /* printf("entry %d for %d\n",entries,locc); */
361 }
362 }
363 }
364
365 #ifdef DEBUG
366
367 twrite(loq) /* travel options from this loc */
368 int loq;
369 { register struct travlist *t;
370 printf("If");
371 speak(<ext[loq]);
372 printf("then\n");
373 for (t=travel[loq]; t!=0; t=t->next)
374 { printf("verb %d takes you to ",t->tverb);
375 if (t->tloc<=300)
376 speak(<ext[t->tloc]);
377 else if (t->tloc<=500)
378 printf("special code %d\n",t->tloc-300);
379 else
380 rspeak(t->tloc-500);
381 printf("under conditions %d\n",t->conditions);
382 }
383 }
384
385 #endif DEBUG
386
387 rvoc()
388 { register char *s; /* read the vocabulary */
389 register int index;
390 char buf[6];
391 for (;;)
392 { index=rnum();
393 if (index<0) break;
394 for (s=buf,*s=0;; s++) /* get the word */
395 if ((*s=next())==TAB || *s=='\n' || *s==LF
396 || *s==' ') break;
397 /* terminate word with newline, LF, tab, blank */
398 if (*s!='\n' && *s!=LF) FLUSHLF; /* can be comments */
399 *s=0;
400 /* printf("\"%s\"=%d\n",buf,index);*/
401 vocab(buf,-2,index);
402 }
403 /* prht(); */
404 }
405
406
407 rlocs() /* initial object locations */
408 { for (;;)
409 { if ((obj=rnum())<0) break;
410 plac[obj]=rnum(); /* initial loc for this obj */
411 if (breakch==TAB) /* there's another entry */
412 fixd[obj]=rnum();
413 else fixd[obj]=0;
414 }
415 }
416
417 rdflt() /* default verb messages */
418 { for (;;)
419 { if ((verb=rnum())<0) break;
420 actspk[verb]=rnum();
421 }
422 }
423
424 rliq() /* liquid assets &c: cond bits */
425 { register int bitnum;
426 for (;;) /* read new bit list */
427 { if ((bitnum=rnum())<0) break;
428 for (;;) /* read locs for bits */
429 { cond[rnum()] |= setbit[bitnum];
430 if (breakch==LF) break;
431 }
432 }
433 }
434
435 rhints()
436 { register int hintnum,i;
437 hntmax=0;
438 for (;;)
439 { if ((hintnum=rnum())<0) break;
440 for (i=1; i<5; i++)
441 hints[hintnum][i]=rnum();
442 if (hintnum>hntmax) hntmax=hintnum;
443 }
444 }
445
446
447 rspeak(msg)
448 int msg;
449 { if (msg!=0) speak(&rtext[msg]);
450 }
451
452
453 mspeak(msg)
454 int msg;
455 { if (msg!=0) speak(&mtext[msg]);
456 }
457
458
459 speak(msg) /* read, decrypt, and print a message (not ptext) */
460 struct text *msg;/* msg is a pointer to seek address and length of mess */
461 {
462 register char *s, nonfirst;
463
464 s = msg->seekadr;
465 nonfirst=0;
466 while (s - msg->seekadr < msg->txtlen) /* read a line at a time */
467 { tape=iotape; /* restart decryption tape */
468 while ((*s++ ^ *tape++) != TAB); /* read past loc num */
469 /* assume tape is longer than location number */
470 /* plus the lookahead put together */
471 if ((*s ^ *tape) == '>' &&
472 (*(s+1) ^ *(tape+1)) == '$' &&
473 (*(s+2) ^ *(tape+2)) == '<') break;
474 if (blklin && !nonfirst++) putchar('\n');
475 do
476 { if (*tape == 0) tape = iotape;/* rewind decryp tape */
477 putchar(*s ^ *tape);
478 } while ((*s++ ^ *tape++) != LF); /* better end with LF */
479 }
480 }
481
482
483 pspeak(m,skip) /* read, decrypt an print a ptext message */
484 int m; /* msg is the number of all the p msgs for this place */
485 int skip; /* assumes object 1 doesn't have prop 1, obj 2 no prop 2 &c*/
486 {
487 register char *s,nonfirst;
488 char *numst, save;
489 struct text *msg;
490 char *tbuf;
491
492 msg = &ptext[m];
493 if ((tbuf=(char *) malloc(msg->txtlen + 1)) == 0) bug(108);
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 }
521