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