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