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