1 /* $OpenBSD: cypher.c,v 1.16 2007/09/09 17:10:02 ray Exp $ */ 2 /* $NetBSD: cypher.c,v 1.3 1995/03/21 15:07:15 cgd Exp $ */ 3 4 /* 5 * Copyright (c) 1983, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)cypher.c 8.2 (Berkeley) 4/28/95"; 36 #else 37 static char rcsid[] = "$OpenBSD: cypher.c,v 1.16 2007/09/09 17:10:02 ray Exp $"; 38 #endif 39 #endif /* not lint */ 40 41 #include <stdarg.h> 42 43 #include "extern.h" 44 #include "pathnames.h" 45 46 static void verb_with_all(unsigned int *, int, int (*)(void), const char *); 47 48 /* 49 * Prompt user to input an integer, which is stored in *value. 50 * On failure prints a warning, leaves *value untouched, and returns -1. 51 */ 52 int 53 getnum(int *value, const char *fmt, ...) 54 { 55 char buffer[BUFSIZ]; 56 va_list ap; 57 const char *errstr; 58 int n; 59 60 va_start(ap, fmt); 61 vprintf(fmt, ap); 62 fflush(stdout); 63 va_end(ap); 64 65 if (fgets(buffer, sizeof(buffer), stdin) == NULL) { 66 warnx("error reading input"); 67 return (-1); 68 } 69 buffer[strcspn(buffer, "\n")] = '\0'; 70 71 n = strtonum(buffer, INT_MIN, INT_MAX, &errstr); 72 if (errstr) { 73 warnx("number %s: %s", errstr, buffer); 74 return (-1); 75 } 76 *value = n; 77 return (0); 78 } 79 80 /* returns 0 if error or no more commands to do, 81 * 1 if there are more commands remaining on the current input line 82 */ 83 int 84 cypher(void) 85 { 86 int n; 87 int junk; 88 int lflag = -1; 89 char *filename, *rfilename; 90 size_t filename_len; 91 92 while (wordnumber <= wordcount) { 93 if (wordtype[wordnumber] != VERB && 94 !(wordtype[wordnumber] == OBJECT && 95 wordvalue[wordnumber] == KNIFE)) { 96 printf("%s: How's that?\n", 97 (wordnumber == wordcount) ? words[wordnumber - 1] : words[wordnumber]); 98 return (0); 99 } 100 101 switch (wordvalue[wordnumber]) { 102 103 case AUXVERB: 104 /* Take the following word as the verb */ 105 wordnumber++; 106 return(cypher()); 107 break; 108 109 case UP: 110 if (location[position].access || wiz || tempwiz) { 111 if (!location[position].access) 112 puts("Zap! A gust of wind lifts you up."); 113 if (!moveplayer(location[position].up, AHEAD)) 114 return (0); 115 } else { 116 puts("There is no way up."); 117 return (0); 118 } 119 lflag = 0; 120 break; 121 122 case DOWN: 123 if (!moveplayer(location[position].down, AHEAD)) 124 return (0); 125 lflag = 0; 126 break; 127 128 case LEFT: 129 if (!moveplayer(left, LEFT)) 130 return (0); 131 lflag = 0; 132 break; 133 134 case RIGHT: 135 if (!moveplayer(right, RIGHT)) 136 return (0); 137 lflag = 0; 138 break; 139 140 case AHEAD: 141 if (!moveplayer(ahead, AHEAD)) 142 return (0); 143 lflag = 0; 144 break; 145 146 case BACK: 147 if (!moveplayer(back, BACK)) 148 return (0); 149 lflag = 0; 150 break; 151 152 case SHOOT: 153 verb_with_all(location[position].objects, OBJ_PERSON, 154 shoot, "shoot at"); 155 break; 156 157 case TAKE: 158 if (wordnumber < wordcount && wordvalue[wordnumber + 1] == EVERYTHING) { 159 int things; 160 things = 0; 161 for (n = 0; n < NUMOFOBJECTS; n++) 162 if (TestBit(location[position].objects, n) && objsht[n]) { 163 things++; 164 wordvalue[wordnumber + 1] = n; 165 /* Some objects (type NOUNS) have special treatment in take(). For these 166 * we must set the type to NOUNS. However for SWORD and BODY all it does 167 * is find which of many objects is meant, so we need do nothing here. 168 * BATHGOD must become NORMGOD as well. NOUNS with no special case must be 169 * included here to get the right error. DOOR cannot occur as an object so 170 * need not be included. 171 */ 172 switch (n) { 173 case BATHGOD: 174 wordvalue[wordnumber + 1] = NORMGOD; 175 /* FALLTHROUGH */ 176 case NORMGOD: 177 case AMULET: 178 case MEDALION: 179 case TALISMAN: 180 case MAN: 181 case TIMER: 182 case NATIVE: 183 wordtype[wordnumber + 1] = NOUNS; 184 break; 185 default: 186 wordtype[wordnumber + 1] = OBJECT; 187 } 188 wordnumber = take(location[position].objects); 189 wordnumber += 2; 190 } 191 if (!things) 192 puts("Nothing to take!"); 193 } else 194 take(location[position].objects); 195 break; 196 197 case DROP: 198 if (wordnumber < wordcount && wordvalue[wordnumber + 1] == EVERYTHING) { 199 int things; 200 things = 0; 201 for (n = 0; n < NUMOFOBJECTS; n++) 202 if (TestBit(inven, n)) { 203 things++; 204 wordvalue[wordnumber + 1] = n; 205 wordnumber = drop("Dropped"); 206 } 207 wordnumber++; 208 wordnumber++; 209 if (!things) 210 puts("Nothing to drop!"); 211 } else 212 drop("Dropped"); 213 break; 214 215 216 case KICK: 217 case THROW: 218 if (wordnumber < wordcount && wordvalue[wordnumber + 1] == EVERYTHING) { 219 int things, wv; 220 things = 0; 221 wv = wordvalue[wordnumber]; 222 for (n = 0; n < NUMOFOBJECTS; n++) 223 if (TestBit(inven, n) || 224 (TestBit(location[position].objects, n) && objsht[n])) { 225 things++; 226 wordvalue[wordnumber + 1] = n; 227 wordnumber = throw(wordvalue[wordnumber] == KICK ? "Kicked" : "Thrown"); 228 } 229 wordnumber += 2; 230 if (!things) 231 printf("Nothing to %s!\n", wv == KICK ? "kick" : "throw"); 232 } else 233 throw(wordvalue[wordnumber] == KICK ? "Kicked" : "Thrown"); 234 break; 235 236 case TAKEOFF: 237 verb_with_all(wear, 0, takeoff, "take off"); 238 break; 239 240 case DRAW: 241 verb_with_all(wear, 0, draw, "draw"); 242 break; 243 244 case PUTON: 245 verb_with_all(location[position].objects, 0, puton, "put on"); 246 break; 247 248 case WEARIT: 249 verb_with_all(inven, 0, wearit, "wear"); 250 break; 251 252 case EAT: 253 verb_with_all(inven, 0, eat, "eat"); 254 break; 255 256 case PUT: 257 put(); 258 break; 259 260 case INVEN: 261 if (ucard(inven)) { 262 puts("You are holding:\n"); 263 for (n = 0; n < NUMOFOBJECTS; n++) 264 if (TestBit(inven, n)) 265 printf("\t%s\n", objsht[n]); 266 printf("\n= %d kilogram%s ", carrying, 267 (carrying == 1 ? "." : "s.")); 268 if (WEIGHT) 269 printf("(%d%%)\n", carrying * 100 / WEIGHT); 270 else 271 printf("(can't lift any weight%s)\n", 272 (carrying ? " or move with what you have" : "")); 273 if (CUMBER) 274 printf("Your arms are %d%% full.\n", 275 encumber * 100 / CUMBER); 276 else 277 printf("You can't pick anything up.\n"); 278 } else 279 puts("You aren't carrying anything."); 280 281 if (ucard(wear)) { 282 puts("\nYou are wearing:\n"); 283 for (n = 0; n < NUMOFOBJECTS; n++) 284 if (TestBit(wear, n)) 285 printf("\t%s\n", objsht[n]); 286 } else 287 puts("\nYou are stark naked."); 288 if (card(injuries, NUMOFINJURIES)) { 289 puts("\nYou have suffered:\n"); 290 for (n = 0; n < NUMOFINJURIES; n++) 291 if (injuries[n]) 292 printf("\t%s\n", ouch[n]); 293 printf("\nYou can still carry up to %d kilogram%s\n", WEIGHT, (WEIGHT == 1 ? "." : "s.")); 294 } else 295 puts("\nYou are in perfect health."); 296 break; 297 298 case USE: 299 lflag = use(); 300 break; 301 302 case OPEN: 303 dooropen(); 304 break; 305 306 case LOOK: 307 if (!notes[CANTSEE] || TestBit(inven, LAMPON) || 308 TestBit(location[position].objects, LAMPON) 309 || matchlight) { 310 beenthere[position] = 2; 311 writedes(); 312 printobjs(); 313 if (matchlight) { 314 puts("\nYour match splutters out."); 315 matchlight = 0; 316 } 317 } else 318 puts("I can't see anything."); 319 return (0); /* No commands after a look */ 320 break; 321 322 case SU: 323 if (wiz || tempwiz) { 324 getnum(&position, "\nRoom (was %d) = ", position); 325 getnum(&ourtime, "Time (was %d) = ", ourtime); 326 getnum(&fuel, "Fuel (was %d) = ", fuel); 327 getnum(&torps, "Torps (was %d) = ", torps); 328 getnum(&CUMBER, "CUMBER (was %d) = ", CUMBER); 329 getnum(&WEIGHT, "WEIGHT (was %d) = ", WEIGHT); 330 getnum(&ourclock, "Clock (was %d) = ", ourclock); 331 if (getnum(&junk, "Wizard (was %d, %d) = ", wiz, tempwiz) != -1 && !junk) 332 tempwiz = wiz = 0; 333 printf("\nDONE.\n"); 334 return (0); /* No commands after a SU */ 335 } else 336 puts("You aren't a wizard."); 337 break; 338 339 case SCORE: 340 printf("\tPLEASURE\tPOWER\t\tEGO\n"); 341 printf("\t%3d\t\t%3d\t\t%3d\n\n", pleasure, power, ego); 342 printf("This gives you the rating of %s in %d turns.\n", rate(), ourtime); 343 printf("You have visited %d out of %d rooms this run (%d%%).\n", card(beenthere, NUMOFROOMS), NUMOFROOMS, card(beenthere, NUMOFROOMS) * 100 / NUMOFROOMS); 344 break; 345 346 /* case KNIFE: */ 347 case KILL: 348 murder(); 349 break; 350 351 case UNDRESS: 352 undress(); 353 break; 354 355 case RAVAGE: 356 ravage(); 357 break; 358 359 case SAVE: 360 printf("\nSave file name (default %s): ", 361 DEFAULT_SAVE_FILE); 362 filename = fgetln(stdin, &filename_len); 363 if (filename_len == 0 364 || (filename_len == 1 && filename[0] == '\n')) 365 rfilename = save_file_name(DEFAULT_SAVE_FILE, 366 strlen(DEFAULT_SAVE_FILE)); 367 else { 368 if (filename[filename_len - 1] == '\n') 369 filename_len--; 370 rfilename = save_file_name(filename, 371 filename_len); 372 } 373 save(rfilename); 374 free(rfilename); 375 break; 376 377 case VERBOSE: 378 verbose = 1; 379 printf("[Maximum verbosity]\n"); 380 break; 381 382 case BRIEF: 383 verbose = 0; 384 printf("[Standard verbosity]\n"); 385 break; 386 387 case FOLLOW: 388 lflag = follow(); 389 break; 390 391 case GIVE: 392 give(); 393 break; 394 395 case KISS: 396 kiss(); 397 break; 398 399 case LOVE: 400 love(); 401 break; 402 403 case RIDE: 404 lflag = ride(); 405 break; 406 407 case DRIVE: 408 lflag = drive(); 409 break; 410 411 case LIGHT: 412 light(); 413 break; 414 415 case LAUNCH: 416 if (!launch()) 417 return (0); 418 else 419 lflag = 0; 420 break; 421 422 case LANDIT: 423 if (!land()) 424 return (0); 425 else 426 lflag = 0; 427 break; 428 429 case TIME: 430 chime(); 431 break; 432 433 case SLEEP: 434 zzz(); 435 break; 436 437 case DIG: 438 dig(); 439 break; 440 441 case JUMP: 442 lflag = jump(); 443 break; 444 445 case BURY: 446 bury(); 447 break; 448 449 case SWIM: 450 puts("Surf's up!"); 451 break; 452 453 case DRINK: 454 drink(); 455 break; 456 457 case QUIT: 458 die(0); 459 460 default: 461 puts("How's that?"); 462 return (0); 463 break; 464 465 } 466 if (!lflag) 467 newlocation(); 468 if (wordnumber < wordcount && !stop_cypher && 469 (*words[wordnumber] == ',' || *words[wordnumber] == '.')) { 470 wordnumber++; 471 return (1); 472 } else 473 return (0); 474 } 475 return (0); 476 } 477 478 int 479 inc_wordnumber(const char *v, const char *adv) 480 { 481 wordnumber++; 482 if (wordnumber >= wordcount) { 483 printf("%c%s %s?\n", toupper(v[0]), v + 1, adv); 484 return(-1); 485 } 486 return(0); 487 } 488 489 static void 490 verb_with_all(unsigned int *testarray, int objflg, int (*verbfunc)(void), 491 const char *verbname) 492 { 493 int things, n; 494 495 things = 0; 496 if (wordnumber < wordcount && wordvalue[wordnumber + 1] == EVERYTHING) { 497 for (n = 0; n < NUMOFOBJECTS; n++) 498 if (TestBit(testarray, n) && 499 (objsht[n] || (objflg & objflags[n]))) { 500 things++; 501 wordvalue[wordnumber + 1] = n; 502 /* Assume it's a NOUN if no short description */ 503 if (objsht[n]) 504 wordtype[wordnumber + 1] = OBJECT; 505 else 506 wordtype[wordnumber + 1] = NOUNS; 507 wordnumber = verbfunc(); 508 } 509 wordnumber += 2; 510 if (!things) 511 printf("Nothing to %s!\n", verbname); 512 } else 513 verbfunc(); 514 } 515