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