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