Commit | Line | Data |
---|---|---|
da1ddb48 | 1 | /*- |
49016dbd | 2 | * Copyright (c) 1991, 1993 The Regents of the University of California. |
da1ddb48 KB |
3 | * All rights reserved. |
4 | * | |
49016dbd KB |
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. | |
da1ddb48 KB |
9 | * |
10 | * %sccs.include.redist.c% | |
11 | */ | |
12 | ||
13 | #ifndef lint | |
49016dbd | 14 | static char sccsid[] = "@(#)io.c 5.2 (Berkeley) %G%"; |
da1ddb48 | 15 | #endif /* not lint */ |
f2b5c7ab | 16 | |
da1ddb48 | 17 | /* Re-coding of advent in C: file i/o and user i/o */ |
f2b5c7ab RH |
18 | |
19 | #include "hdr.h" | |
20 | #include <stdio.h> | |
21 | ||
22 | ||
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 | ||
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 | ||
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 | ||
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 | ||
49016dbd KB |
113 | /* FILE *inbuf,*outbuf; */ |
114 | ||
115 | char *inptr; /* Pointer into virtual disk */ | |
f2b5c7ab | 116 | |
f2b5c7ab RH |
117 | int outsw = 0; /* putting stuff to data file? */ |
118 | ||
49016dbd | 119 | char iotape[] = "Ax3F'\003tt$8h\315qer*h\017nGKrX\207:!l"; |
f2b5c7ab RH |
120 | char *tape = iotape; /* pointer to encryption tape */ |
121 | ||
49016dbd KB |
122 | next() /* next virtual char, bump adr */ |
123 | { | |
124 | int ch; | |
125 | ||
126 | ch=(*inptr ^ random()) & 0xFF; /* Decrypt input data */ | |
f2b5c7ab | 127 | if (outsw) /* putting data in tmp file */ |
49016dbd KB |
128 | { if (*tape==0) tape=iotape; /* rewind encryption tape */ |
129 | *inptr = ch ^ *tape++; /* re-encrypt and replace value */ | |
f2b5c7ab | 130 | } |
49016dbd | 131 | inptr++; |
f2b5c7ab RH |
132 | return(ch); |
133 | } | |
134 | ||
f2b5c7ab RH |
135 | char breakch; /* tell which char ended rnum */ |
136 | ||
49016dbd | 137 | rdata() /* "read" data from virtual file*/ |
f2b5c7ab RH |
138 | { register int sect; |
139 | register char ch; | |
49016dbd KB |
140 | |
141 | inptr = data_file; /* Pointer to virtual data file */ | |
142 | srandom(SEED); /* which is lightly encrypted. */ | |
143 | ||
144 | clsses=1; | |
f2b5c7ab RH |
145 | for (;;) /* read data sections */ |
146 | { sect=next()-'0'; /* 1st digit of section number */ | |
49016dbd | 147 | #ifdef VERBOSE |
f2b5c7ab | 148 | printf("Section %c",sect+'0'); |
49016dbd | 149 | #endif |
f2b5c7ab | 150 | if ((ch=next())!=LF) /* is there a second digit? */ |
49016dbd KB |
151 | { |
152 | FLUSHLF; | |
153 | #ifdef VERBOSE | |
f2b5c7ab | 154 | putchar(ch); |
49016dbd | 155 | #endif |
f2b5c7ab RH |
156 | sect=10*sect+ch-'0'; |
157 | } | |
49016dbd | 158 | #ifdef VERBOSE |
f2b5c7ab | 159 | putchar('\n'); |
49016dbd | 160 | #endif |
f2b5c7ab RH |
161 | switch(sect) |
162 | { case 0: /* finished reading database */ | |
f2b5c7ab RH |
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 | ||
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 | ||
49016dbd | 219 | char *seekhere; |
f2b5c7ab RH |
220 | |
221 | rdesc(sect) /* read description-format msgs */ | |
222 | int sect; | |
223 | { register char *s,*t; | |
224 | register int locc; | |
49016dbd | 225 | char *seekstart, *maystart, *adrstart; |
f2b5c7ab | 226 | char *entry; |
49016dbd KB |
227 | |
228 | seekhere = inptr; /* Where are we in virtual file?*/ | |
f2b5c7ab | 229 | outsw=1; /* these msgs go into tmp file */ |
f2b5c7ab | 230 | for (oldloc= -1, seekstart=seekhere;;) |
49016dbd | 231 | { maystart=inptr; /* maybe starting new entry */ |
f2b5c7ab RH |
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 | ||
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 | ||
49016dbd | 333 | #ifdef DEBUG |
f2b5c7ab RH |
334 | |
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 | ||
49016dbd | 353 | #endif DEBUG |
f2b5c7ab RH |
354 | |
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 | ||
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 | ||
385 | rdflt() /* default verb messages */ | |
386 | { for (;;) | |
387 | { if ((verb=rnum())<0) break; | |
388 | actspk[verb]=rnum(); | |
389 | } | |
390 | } | |
391 | ||
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 | ||
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 | ||
415 | rspeak(msg) | |
416 | int msg; | |
417 | { if (msg!=0) speak(&rtext[msg]); | |
418 | } | |
419 | ||
420 | ||
421 | mspeak(msg) | |
422 | int msg; | |
423 | { if (msg!=0) speak(&mtext[msg]); | |
424 | } | |
425 | ||
426 | ||
f2b5c7ab RH |
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 */ | |
49016dbd KB |
429 | { |
430 | register char *s, nonfirst; | |
431 | ||
432 | s = msg->seekadr; | |
f2b5c7ab | 433 | nonfirst=0; |
49016dbd | 434 | while (s - msg->seekadr < msg->txtlen) /* read a line at a time */ |
f2b5c7ab | 435 | { tape=iotape; /* restart decryption tape */ |
49016dbd | 436 | while ((*s++ ^ *tape++) != TAB); /* read past loc num */ |
f2b5c7ab RH |
437 | /* assume tape is longer than location number */ |
438 | /* plus the lookahead put together */ | |
49016dbd KB |
439 | if ((*s ^ *tape) == '>' && |
440 | (*(s+1) ^ *(tape+1)) == '$' && | |
441 | (*(s+2) ^ *(tape+2)) == '<') break; | |
442 | if (blklin && !nonfirst++) putchar('\n'); | |
f2b5c7ab | 443 | do |
49016dbd KB |
444 | { if (*tape == 0) tape = iotape;/* rewind decryp tape */ |
445 | putchar(*s ^ *tape); | |
446 | } while ((*s++ ^ *tape++) != LF); /* better end with LF */ | |
f2b5c7ab | 447 | } |
f2b5c7ab RH |
448 | } |
449 | ||
450 | ||
49016dbd KB |
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 */ | |
f2b5c7ab | 453 | int skip; /* assumes object 1 doesn't have prop 1, obj 2 no prop 2 &c*/ |
49016dbd KB |
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 | ||
f2b5c7ab | 465 | nonfirst=0; |
49016dbd | 466 | while (s - tbuf < msg->txtlen) /* read line at a time */ |
f2b5c7ab RH |
467 | { tape=iotape; /* restart decryption tape */ |
468 | for (numst=s; (*s^= *tape++)!=TAB; s++); /* get number */ | |
49016dbd KB |
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) | |
f2b5c7ab RH |
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 | } |