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