]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - adventure/io.c
Don't allow empty "give" command (without arguments).
[bsdgames-darwin.git] / adventure / io.c
1 /* $NetBSD: io.c,v 1.6 1997/10/11 01:53:29 lukem 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.6 1997/10/11 01:53:29 lukem 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 <stdio.h>
53 #include <string.h>
54 #include <stdlib.h>
55 #include "hdr.h"
56 #include "extern.h"
57
58
59 void
60 getin(wrd1, wrd2) /* get command from user */
61 char **wrd1, **wrd2; /* no prompt, usually */
62 {
63 char *s;
64 static char wd1buf[MAXSTR], wd2buf[MAXSTR];
65 int first, numch;
66
67 *wrd1 = wd1buf; /* return ptr to internal str */
68 *wrd2 = wd2buf;
69 wd2buf[0] = 0; /* in case it isn't set here */
70 for (s = wd1buf, first = 1, numch = 0;;) {
71 if ((*s = getchar()) >= 'A' && *s <= 'Z')
72 *s = *s - ('A' - 'a');
73 /* convert to upper case */
74 switch (*s) { /* start reading from user */
75 case '\n':
76 *s = 0;
77 return;
78 case ' ':
79 if (s == wd1buf || s == wd2buf) /* initial blank */
80 continue;
81 *s = 0;
82 if (first) { /* finished 1st wd; start 2nd */
83 first = numch = 0;
84 s = wd2buf;
85 break;
86 } else { /* finished 2nd word */
87 FLUSHLINE;
88 *s = 0;
89 return;
90 }
91 default:
92 if (++numch >= MAXSTR) { /* string too long */
93 printf("Give me a break!!\n");
94 wd1buf[0] = wd2buf[0] = 0;
95 FLUSHLINE;
96 return;
97 }
98 s++;
99 }
100 }
101 }
102
103 int
104 confirm(mesg) /* confirm irreversible action */
105 char *mesg;
106 {
107 int result;
108 printf("%s", mesg); /* tell him what he did */
109 if (getchar() == 'y') /* was his first letter a 'y'? */
110 result = 1;
111 else
112 result = 0;
113 FLUSHLINE;
114 return (result);
115 }
116
117 int
118 yes(x, y, z) /* confirm with rspeak */
119 int x, y, z;
120 {
121 int result = TRUE; /* pacify gcc */
122 char ch;
123 for (;;) {
124 rspeak(x); /* tell him what we want */
125 if ((ch = getchar()) == 'y')
126 result = TRUE;
127 else
128 if (ch == 'n')
129 result = FALSE;
130 FLUSHLINE;
131 if (ch == 'y' || ch == 'n')
132 break;
133 printf("Please answer the question.\n");
134 }
135 if (result == TRUE)
136 rspeak(y);
137 if (result == FALSE)
138 rspeak(z);
139 return (result);
140 }
141
142 int
143 yesm(x, y, z) /* confirm with mspeak */
144 int x, y, z;
145 {
146 int result = TRUE; /* pacify gcc */
147 char ch;
148 for (;;) {
149 mspeak(x); /* tell him what we want */
150 if ((ch = getchar()) == 'y')
151 result = TRUE;
152 else
153 if (ch == 'n')
154 result = FALSE;
155 FLUSHLINE;
156 if (ch == 'y' || ch == 'n')
157 break;
158 printf("Please answer the question.\n");
159 }
160 if (result == TRUE)
161 mspeak(y);
162 if (result == FALSE)
163 mspeak(z);
164 return (result);
165 }
166 /* FILE *inbuf,*outbuf; */
167
168 char *inptr; /* Pointer into virtual disk */
169
170 int outsw = 0; /* putting stuff to data file? */
171
172 char iotape[] = "Ax3F'\003tt$8h\315qer*h\017nGKrX\207:!l";
173 char *tape = iotape; /* pointer to encryption tape */
174
175 int
176 next()
177 { /* next virtual char, bump adr */
178 int ch;
179
180 ch = (*inptr ^ random()) & 0xFF; /* Decrypt input data */
181 if (outsw) { /* putting data in tmp file */
182 if (*tape == 0)
183 tape = iotape; /* rewind encryption tape */
184 *inptr = ch ^ *tape++; /* re-encrypt and replace value */
185 }
186 inptr++;
187 return (ch);
188 }
189
190 char breakch; /* tell which char ended rnum */
191
192 void
193 rdata()
194 { /* "read" data from virtual file */
195 int sect;
196 char ch;
197
198 inptr = data_file; /* Pointer to virtual data file */
199 srandom(SEED); /* which is lightly encrypted. */
200
201 clsses = 1;
202 for (;;) { /* read data sections */
203 sect = next() - '0'; /* 1st digit of section number */
204 #ifdef VERBOSE
205 printf("Section %c", sect + '0');
206 #endif
207 if ((ch = next()) != LF) { /* is there a second digit? */
208 FLUSHLF;
209 #ifdef VERBOSE
210 putchar(ch);
211 #endif
212 sect = 10 * sect + ch - '0';
213 }
214 #ifdef VERBOSE
215 putchar('\n');
216 #endif
217 switch (sect) {
218 case 0: /* finished reading database */
219 return;
220 case 1: /* long form descriptions */
221 rdesc(1);
222 break;
223 case 2: /* short form descriptions */
224 rdesc(2);
225 break;
226 case 3: /* travel table */
227 rtrav();
228 break;
229 case 4: /* vocabulary */
230 rvoc();
231 break;
232 case 5: /* object descriptions */
233 rdesc(5);
234 break;
235 case 6: /* arbitrary messages */
236 rdesc(6);
237 break;
238 case 7: /* object locations */
239 rlocs();
240 break;
241 case 8: /* action defaults */
242 rdflt();
243 break;
244 case 9: /* liquid assets */
245 rliq();
246 break;
247 case 10: /* class messages */
248 rdesc(10);
249 break;
250 case 11: /* hints */
251 rhints();
252 break;
253 case 12: /* magic messages */
254 rdesc(12);
255 break;
256 default:
257 printf("Invalid data section number: %d\n", sect);
258 for (;;)
259 putchar(next());
260 }
261 if (breakch != LF) /* routines return after "-1" */
262 FLUSHLF;
263 }
264 }
265
266 char nbf[12];
267
268
269 int
270 rnum()
271 { /* read initial location num */
272 char *s;
273 tape = iotape; /* restart encryption tape */
274 for (s = nbf, *s = 0;; s++)
275 if ((*s = next()) == TAB || *s == '\n' || *s == LF)
276 break;
277 breakch = *s; /* save char for rtrav() */
278 *s = 0; /* got the number as ascii */
279 if (nbf[0] == '-')
280 return (-1); /* end of data */
281 return (atoi(nbf)); /* convert it to integer */
282 }
283
284 char *seekhere;
285
286 void
287 rdesc(sect) /* read description-format msgs */
288 int sect;
289 {
290 int locc;
291 char *seekstart, *maystart;
292
293 seekhere = inptr; /* Where are we in virtual file? */
294 outsw = 1; /* these msgs go into tmp file */
295 for (oldloc = -1, seekstart = seekhere;;) {
296 maystart = inptr; /* maybe starting new entry */
297 if ((locc = rnum()) != oldloc && oldloc >= 0 /* finished msg */
298 && !(sect == 5 && (locc == 0 || locc >= 100))) { /* unless sect 5 */
299 switch (sect) { /* now put it into right table */
300 case 1:/* long descriptions */
301 ltext[oldloc].seekadr = seekhere;
302 ltext[oldloc].txtlen = maystart - seekstart;
303 break;
304 case 2:/* short descriptions */
305 stext[oldloc].seekadr = seekhere;
306 stext[oldloc].txtlen = maystart - seekstart;
307 break;
308 case 5:/* object descriptions */
309 ptext[oldloc].seekadr = seekhere;
310 ptext[oldloc].txtlen = maystart - seekstart;
311 break;
312 case 6:/* random messages */
313 if (oldloc > RTXSIZ) {
314 printf("Too many random msgs\n");
315 exit(0);
316 }
317 rtext[oldloc].seekadr = seekhere;
318 rtext[oldloc].txtlen = maystart - seekstart;
319 break;
320 case 10: /* class messages */
321 ctext[clsses].seekadr = seekhere;
322 ctext[clsses].txtlen = maystart - seekstart;
323 cval[clsses++] = oldloc;
324 break;
325 case 12: /* magic messages */
326 if (oldloc > MAGSIZ) {
327 printf("Too many magic msgs\n");
328 exit(0);
329 }
330 mtext[oldloc].seekadr = seekhere;
331 mtext[oldloc].txtlen = maystart - seekstart;
332 break;
333 default:
334 printf("rdesc called with bad section\n");
335 exit(0);
336 }
337 seekhere += maystart - seekstart;
338 }
339 if (locc < 0) {
340 outsw = 0; /* turn off output */
341 seekhere += 3; /* -1<delimiter> */
342 return;
343 }
344 if (sect != 5 || (locc > 0 && locc < 100)) {
345 if (oldloc != locc) /* starting a new message */
346 seekstart = maystart;
347 oldloc = locc;
348 }
349 FLUSHLF; /* scan the line */
350 }
351 }
352
353 void
354 rtrav()
355 { /* read travel table */
356 int locc;
357 struct travlist *t = NULL;
358 char *s;
359 char buf[12];
360 int len, m, n, entries = 0;
361
362 for (oldloc = -1;;) { /* get another line */
363 if ((locc = rnum()) != oldloc && oldloc >= 0) { /* end of entry */
364 t->next = 0; /* terminate the old entry */
365 /* printf("%d:%d entries\n",oldloc,entries); */
366 /* twrite(oldloc); */
367 }
368 if (locc == -1)
369 return;
370 if (locc != oldloc) { /* getting a new entry */
371 t = travel[locc] = (struct travlist *) malloc(sizeof(struct travlist));
372 /* printf("New travel list for %d\n",locc); */
373 entries = 0;
374 oldloc = locc;
375 }
376 for (s = buf;; s++) /* get the newloc number /ASCII */
377 if ((*s = next()) == TAB || *s == LF)
378 break;
379 *s = 0;
380 len = length(buf) - 1; /* quad long number handling */
381 /* printf("Newloc: %s (%d chars)\n",buf,len); */
382 if (len < 4) { /* no "m" conditions */
383 m = 0;
384 n = atoi(buf); /* newloc mod 1000 = newloc */
385 } else { /* a long integer */
386 n = atoi(buf + len - 3);
387 buf[len - 3] = 0; /* terminate newloc/1000 */
388 m = atoi(buf);
389 }
390 while (breakch != LF) { /* only do one line at a time */
391 if (entries++)
392 t = t->next = (struct travlist *) malloc(sizeof(struct travlist));
393 t->tverb = rnum(); /* get verb from the file */
394 t->tloc = n; /* table entry mod 1000 */
395 t->conditions = m; /* table entry / 1000 */
396 /* printf("entry %d for %d\n",entries,locc); */
397 }
398 }
399 }
400 #ifdef DEBUG
401
402 void
403 twrite(loq) /* travel options from this loc */
404 int loq;
405 {
406 struct travlist *t;
407 printf("If");
408 speak(&ltext[loq]);
409 printf("then\n");
410 for (t = travel[loq]; t != 0; t = t->next) {
411 printf("verb %d takes you to ", t->tverb);
412 if (t->tloc <= 300)
413 speak(&ltext[t->tloc]);
414 else
415 if (t->tloc <= 500)
416 printf("special code %d\n", t->tloc - 300);
417 else
418 rspeak(t->tloc - 500);
419 printf("under conditions %d\n", t->conditions);
420 }
421 }
422 #endif /* DEBUG */
423
424 void
425 rvoc()
426 {
427 char *s; /* read the vocabulary */
428 int index;
429 char buf[6];
430 for (;;) {
431 index = rnum();
432 if (index < 0)
433 break;
434 for (s = buf, *s = 0;; s++) /* get the word */
435 if ((*s = next()) == TAB || *s == '\n' || *s == LF
436 || *s == ' ')
437 break;
438 /* terminate word with newline, LF, tab, blank */
439 if (*s != '\n' && *s != LF)
440 FLUSHLF;/* can be comments */
441 *s = 0;
442 /* printf("\"%s\"=%d\n",buf,index); */
443 vocab(buf, -2, index);
444 }
445 /* prht(); */
446 }
447
448
449 void
450 rlocs()
451 { /* initial object locations */
452 for (;;) {
453 if ((obj = rnum()) < 0)
454 break;
455 plac[obj] = rnum(); /* initial loc for this obj */
456 if (breakch == TAB) /* there's another entry */
457 fixd[obj] = rnum();
458 else
459 fixd[obj] = 0;
460 }
461 }
462
463 void
464 rdflt()
465 { /* default verb messages */
466 for (;;) {
467 if ((verb = rnum()) < 0)
468 break;
469 actspk[verb] = rnum();
470 }
471 }
472
473 void
474 rliq()
475 { /* liquid assets &c: cond bits */
476 int bitnum;
477 for (;;) { /* read new bit list */
478 if ((bitnum = rnum()) < 0)
479 break;
480 for (;;) { /* read locs for bits */
481 cond[rnum()] |= setbit[bitnum];
482 if (breakch == LF)
483 break;
484 }
485 }
486 }
487
488 void
489 rhints()
490 {
491 int hintnum, i;
492 hntmax = 0;
493 for (;;) {
494 if ((hintnum = rnum()) < 0)
495 break;
496 for (i = 1; i < 5; i++)
497 hints[hintnum][i] = rnum();
498 if (hintnum > hntmax)
499 hntmax = hintnum;
500 }
501 }
502
503
504 void
505 rspeak(msg)
506 int msg;
507 {
508 if (msg != 0)
509 speak(&rtext[msg]);
510 }
511
512
513 void
514 mspeak(msg)
515 int msg;
516 {
517 if (msg != 0)
518 speak(&mtext[msg]);
519 }
520
521
522 void
523 speak(msg) /* read, decrypt, and print a message (not
524 * ptext) */
525 struct text *msg; /* msg is a pointer to seek address and length
526 * of mess */
527 {
528 char *s, nonfirst;
529
530 s = msg->seekadr;
531 nonfirst = 0;
532 while (s - msg->seekadr < msg->txtlen) { /* read a line at a time */
533 tape = iotape; /* restart decryption tape */
534 while ((*s++ ^ *tape++) != TAB); /* read past loc num */
535 /* assume tape is longer than location number */
536 /* plus the lookahead put together */
537 if ((*s ^ *tape) == '>' &&
538 (*(s + 1) ^ *(tape + 1)) == '$' &&
539 (*(s + 2) ^ *(tape + 2)) == '<')
540 break;
541 if (blklin && !nonfirst++)
542 putchar('\n');
543 do {
544 if (*tape == 0)
545 tape = iotape; /* rewind decryp tape */
546 putchar(*s ^ *tape);
547 } while ((*s++ ^ *tape++) != LF); /* better end with LF */
548 }
549 }
550
551
552 void
553 pspeak(m, skip) /* read, decrypt an print a ptext message */
554 int m; /* msg is the number of all the p msgs for
555 * this place */
556 int skip; /* assumes object 1 doesn't have prop 1, obj 2
557 * no prop 2 &c */
558 {
559 char *s, nonfirst;
560 char *numst, save;
561 struct text *msg;
562 char *tbuf;
563
564 msg = &ptext[m];
565 if ((tbuf = (char *) malloc(msg->txtlen + 1)) == 0)
566 bug(108);
567 memcpy(tbuf, msg->seekadr, msg->txtlen + 1); /* Room to null */
568 s = tbuf;
569
570 nonfirst = 0;
571 while (s - tbuf < msg->txtlen) { /* read line at a time */
572 tape = iotape; /* restart decryption tape */
573 for (numst = s; (*s ^= *tape++) != TAB; s++); /* get number */
574
575 save = *s; /* Temporarily trash the string (cringe) */
576 *s++ = 0; /* decrypting number within the string */
577
578 if (atoi(numst) != 100 * skip && skip >= 0) {
579 while ((*s++ ^ *tape++) != LF) /* flush the line */
580 if (*tape == 0)
581 tape = iotape;
582 continue;
583 }
584 if ((*s ^ *tape) == '>' && (*(s + 1) ^ *(tape + 1)) == '$' &&
585 (*(s + 2) ^ *(tape + 2)) == '<')
586 break;
587 if (blklin && !nonfirst++)
588 putchar('\n');
589 do {
590 if (*tape == 0)
591 tape = iotape;
592 putchar(*s ^ *tape);
593 } while ((*s++ ^ *tape++) != LF); /* better end with LF */
594 if (skip < 0)
595 break;
596 }
597 free(tbuf);
598 }