4.4BSD snapshot (revision 8.1)
[unix-history] / usr / src / games / adventure / io.c
CommitLineData
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 14static 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
23getin(wrd1,wrd2) /* get command from user */
24char **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
66confirm(mesg) /* confirm irreversible action */
67char *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
77yes(x,y,z) /* confirm with rspeak */
78int 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
95yesm(x,y,z) /* confirm with mspeak */
96int 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
115char *inptr; /* Pointer into virtual disk */
f2b5c7ab 116
f2b5c7ab
RH
117int outsw = 0; /* putting stuff to data file? */
118
49016dbd 119char iotape[] = "Ax3F'\003tt$8h\315qer*h\017nGKrX\207:!l";
f2b5c7ab
RH
120char *tape = iotape; /* pointer to encryption tape */
121
49016dbd
KB
122next() /* 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
135char breakch; /* tell which char ended rnum */
136
49016dbd 137rdata() /* "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
204char nbf[12];
205
206
207rnum() /* 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 219char *seekhere;
f2b5c7ab
RH
220
221rdesc(sect) /* read description-format msgs */
222int 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
289rtrav() /* 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
335twrite(loq) /* travel options from this loc */
336int loq;
337{ register struct travlist *t;
338 printf("If");
339 speak(&ltext[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(&ltext[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
355rvoc()
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
375rlocs() /* 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
385rdflt() /* default verb messages */
386{ for (;;)
387 { if ((verb=rnum())<0) break;
388 actspk[verb]=rnum();
389 }
390}
391
392rliq() /* 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
403rhints()
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
415rspeak(msg)
416int msg;
417{ if (msg!=0) speak(&rtext[msg]);
418}
419
420
421mspeak(msg)
422int msg;
423{ if (msg!=0) speak(&mtext[msg]);
424}
425
426
f2b5c7ab
RH
427speak(msg) /* read, decrypt, and print a message (not ptext) */
428struct 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
451pspeak(m,skip) /* read, decrypt an print a ptext message */
452int m; /* msg is the number of all the p msgs for this place */
f2b5c7ab 453int 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}