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