Home | History | Annotate | Line # | Download | only in wump
wump.c revision 1.2
      1 /*
      2  * Copyright (c) 1989 The Regents of the University of California.
      3  * Copyright (c) 1989 Dave Taylor, Intuitive Systems.
      4  * All rights reserved.
      5  *
      6  * This code is derived from software contributed to Berkeley by
      7  * Dave Taylor, of Intuitive Systems.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. All advertising materials mentioning features or use of this software
     18  *    must display the following acknowledgement:
     19  *	This product includes software developed by the University of
     20  *	California, Berkeley and its contributors.
     21  * 4. Neither the name of the University nor the names of its contributors
     22  *    may be used to endorse or promote products derived from this software
     23  *    without specific prior written permission.
     24  *
     25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     35  * SUCH DAMAGE.
     36  */
     37 
     38 #ifndef lint
     39 char copyright[] =
     40 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
     41  All rights reserved.\n";
     42 #endif /* not lint */
     43 
     44 #ifndef lint
     45 /*static char sccsid[] = "from: @(#)wump.c	4.3 (Berkeley) 6/1/90";*/
     46 static char rcsid[] = "$Id: wump.c,v 1.2 1993/08/01 18:49:20 mycroft Exp $";
     47 #endif /* not lint */
     48 
     49 /*
     50  * A very new version of the age old favorite Hunt-The-Wumpus game that has
     51  * been a part of the BSD distribution of Unix for longer than us old folk
     52  * would care to remember.
     53  */
     54 
     55 #include <sys/types.h>
     56 #include <sys/file.h>
     57 #include <stdio.h>
     58 #include "pathnames.h"
     59 
     60 /* some defines to spec out what our wumpus cave should look like */
     61 
     62 #define	MAX_ARROW_SHOT_DISTANCE	6		/* +1 for '0' stopper */
     63 #define	MAX_LINKS_IN_ROOM	25		/* a complex cave */
     64 
     65 #define	MAX_ROOMS_IN_CAVE	250
     66 #define	ROOMS_IN_CAVE		20
     67 #define	MIN_ROOMS_IN_CAVE	10
     68 
     69 #define	LINKS_IN_ROOM		3
     70 #define	NUMBER_OF_ARROWS	5
     71 #define	PIT_COUNT		3
     72 #define	BAT_COUNT		3
     73 
     74 #define	EASY			1		/* levels of play */
     75 #define	HARD			2
     76 
     77 /* some macro definitions for cleaner output */
     78 
     79 #define	plural(n)	(n == 1 ? "" : "s")
     80 
     81 /* simple cave data structure; +1 so we can index from '1' not '0' */
     82 struct room_record {
     83 	int tunnel[MAX_LINKS_IN_ROOM];
     84 	int has_a_pit, has_a_bat;
     85 } cave[MAX_ROOMS_IN_CAVE+1];
     86 
     87 /*
     88  * global variables so we can keep track of where the player is, how
     89  * many arrows they still have, where el wumpo is, and so on...
     90  */
     91 int player_loc = -1;			/* player location */
     92 int wumpus_loc = -1;			/* The Bad Guy location */
     93 int level = EASY;			/* level of play */
     94 int arrows_left;			/* arrows unshot */
     95 
     96 #ifdef DEBUG
     97 int debug = 0;
     98 #endif
     99 
    100 int pit_num = PIT_COUNT;		/* # pits in cave */
    101 int bat_num = BAT_COUNT;		/* # bats */
    102 int room_num = ROOMS_IN_CAVE;		/* # rooms in cave */
    103 int link_num = LINKS_IN_ROOM;		/* links per room  */
    104 int arrow_num = NUMBER_OF_ARROWS;	/* arrow inventory */
    105 
    106 char answer[20];			/* user input */
    107 
    108 main(argc, argv)
    109 	int argc;
    110 	char **argv;
    111 {
    112 	extern char *optarg;
    113 	int c;
    114 
    115 #ifdef DEBUG
    116 	while ((c = getopt(argc, argv, "a:b:hp:r:t:d")) != EOF)
    117 #else
    118 	while ((c = getopt(argc, argv, "a:b:hp:r:t:")) != EOF)
    119 #endif
    120 		switch (c) {
    121 		case 'a':
    122 			arrow_num = atoi(optarg);
    123 			break;
    124 		case 'b':
    125 			bat_num = atoi(optarg);
    126 			break;
    127 #ifdef DEBUG
    128 		case 'd':
    129 			debug = 1;
    130 			break;
    131 #endif
    132 		case 'h':
    133 			level = HARD;
    134 			break;
    135 		case 'p':
    136 			pit_num = atoi(optarg);
    137 			break;
    138 		case 'r':
    139 			room_num = atoi(optarg);
    140 			if (room_num < MIN_ROOMS_IN_CAVE) {
    141 				(void)fprintf(stderr,
    142 	"No self-respecting wumpus would live in such a small cave!\n");
    143 				exit(1);
    144 			}
    145 			if (room_num > MAX_ROOMS_IN_CAVE) {
    146 				(void)fprintf(stderr,
    147 	"Even wumpii can't furnish caves that large!\n");
    148 				exit(1);
    149 			}
    150 			break;
    151 		case 't':
    152 			link_num = atoi(optarg);
    153 			if (link_num < 2) {
    154 				(void)fprintf(stderr,
    155 	"Wumpii like extra doors in their caves!\n");
    156 				exit(1);
    157 			}
    158 			break;
    159 		case '?':
    160 		default:
    161 			usage();
    162 	}
    163 
    164 	if (link_num > MAX_LINKS_IN_ROOM ||
    165 	    link_num > room_num - (room_num / 4)) {
    166 		(void)fprintf(stderr,
    167 "Too many tunnels!  The cave collapsed!\n(Fortunately, the wumpus escaped!)\n");
    168 		exit(1);
    169 	}
    170 
    171 	if (level == HARD) {
    172 		bat_num += ((random() % (room_num / 2)) + 1);
    173 		pit_num += ((random() % (room_num / 2)) + 1);
    174 	}
    175 
    176 	if (bat_num > room_num / 2) {
    177 		(void)fprintf(stderr,
    178 "The wumpus refused to enter the cave, claiming it was too crowded!\n");
    179 		exit(1);
    180 	}
    181 
    182 	if (pit_num > room_num / 2) {
    183 		(void)fprintf(stderr,
    184 "The wumpus refused to enter the cave, claiming it was too dangerous!\n");
    185 		exit(1);
    186 	}
    187 
    188 	instructions();
    189 	cave_init();
    190 
    191 	/* and we're OFF!  da dum, da dum, da dum, da dum... */
    192 	(void)printf(
    193 "\nYou're in a cave with %d rooms and %d tunnels leading from each room.\n\
    194 There are %d bat%s and %d pit%s scattered throughout the cave, and your\n\
    195 quiver holds %d custom super anti-evil Wumpus arrows.  Good luck.\n",
    196 	    room_num, link_num, bat_num, plural(bat_num), pit_num,
    197 	    plural(pit_num), arrow_num);
    198 
    199 	for (;;) {
    200 		initialize_things_in_cave();
    201 		arrows_left = arrow_num;
    202 		do {
    203 			display_room_stats();
    204 			(void)printf("Move or shoot? (m-s) ");
    205 			(void)fflush(stdout);
    206 			if (!fgets(answer, sizeof(answer), stdin))
    207 				break;
    208 		} while (!take_action());
    209 
    210 		if (!getans("\nCare to play another game? (y-n) "))
    211 			exit(0);
    212 		if (getans("In the same cave? (y-n) "))
    213 			clear_things_in_cave();
    214 		else
    215 			cave_init();
    216 	}
    217 	/* NOTREACHED */
    218 }
    219 
    220 display_room_stats()
    221 {
    222 	register int i;
    223 
    224 	/*
    225 	 * Routine will explain what's going on with the current room, as well
    226 	 * as describe whether there are pits, bats, & wumpii nearby.  It's
    227 	 * all pretty mindless, really.
    228 	 */
    229 	(void)printf(
    230 "\nYou are in room %d of the cave, and have %d arrow%s left.\n",
    231 	    player_loc, arrows_left, plural(arrows_left));
    232 
    233 	if (bats_nearby())
    234 		(void)printf("*rustle* *rustle* (must be bats nearby)\n");
    235 	if (pit_nearby())
    236 		(void)printf("*whoosh* (I feel a draft from some pits).\n");
    237 	if (wump_nearby())
    238 		(void)printf("*sniff* (I can smell the evil Wumpus nearby!)\n");
    239 
    240 	(void)printf("There are tunnels to rooms %d, ",
    241 	   cave[player_loc].tunnel[0]);
    242 
    243 	for (i = 1; i < link_num - 1; i++)
    244 		if (cave[player_loc].tunnel[i] <= room_num)
    245 			(void)printf("%d, ", cave[player_loc].tunnel[i]);
    246 	(void)printf("and %d.\n", cave[player_loc].tunnel[link_num - 1]);
    247 }
    248 
    249 take_action()
    250 {
    251 	/*
    252 	 * Do the action specified by the player, either 'm'ove, 's'hoot
    253 	 * or something exceptionally bizarre and strange!  Returns 1
    254 	 * iff the player died during this turn, otherwise returns 0.
    255 	 */
    256 	switch (*answer) {
    257 		case 'M':
    258 		case 'm':			/* move */
    259 			return(move_to(answer + 1));
    260 		case 'S':
    261 		case 's':			/* shoot */
    262 			return(shoot(answer + 1));
    263 		case 'Q':
    264 		case 'q':
    265 		case 'x':
    266 			exit(0);
    267 		case '\n':
    268 			return(0);
    269 		}
    270 	if (random() % 15 == 1)
    271 		(void)printf("Que pasa?\n");
    272 	else
    273 		(void)printf("I don't understand!\n");
    274 	return(0);
    275 }
    276 
    277 move_to(room_number)
    278 	char *room_number;
    279 {
    280 	int i, just_moved_by_bats, next_room, tunnel_available;
    281 
    282 	/*
    283 	 * This is responsible for moving the player into another room in the
    284 	 * cave as per their directions.  If room_number is a null string,
    285 	 * then we'll prompt the user for the next room to go into.   Once
    286 	 * we've moved into the room, we'll check for things like bats, pits,
    287 	 * and so on.  This routine returns 1 if something occurs that kills
    288 	 * the player and 0 otherwise...
    289 	 */
    290 	tunnel_available = just_moved_by_bats = 0;
    291 	next_room = atoi(room_number);
    292 
    293 	/* crap for magic tunnels */
    294 	if (next_room == room_num + 1 &&
    295 	    cave[player_loc].tunnel[link_num-1] != next_room)
    296 		++next_room;
    297 
    298 	while (next_room < 1 || next_room > room_num + 1) {
    299 		if (next_room < 0 && next_room != -1)
    300 (void)printf("Sorry, but we're constrained to a semi-Euclidean cave!\n");
    301 		if (next_room > room_num + 1)
    302 (void)printf("What?  The cave surely isn't quite that big!\n");
    303 		if (next_room == room_num + 1 &&
    304 		    cave[player_loc].tunnel[link_num-1] != next_room) {
    305 			(void)printf("What?  The cave isn't that big!\n");
    306 			++next_room;
    307 		}
    308 		(void)printf("To which room do you wish to move? ");
    309 		(void)fflush(stdout);
    310 		if (!fgets(answer, sizeof(answer), stdin))
    311 			return(1);
    312 		next_room = atoi(answer);
    313 	}
    314 
    315 	/* now let's see if we can move to that room or not */
    316 	tunnel_available = 0;
    317 	for (i = 0; i < link_num; i++)
    318 		if (cave[player_loc].tunnel[i] == next_room)
    319 			tunnel_available = 1;
    320 
    321 	if (!tunnel_available) {
    322 		(void)printf("*Oof!*  (You hit the wall)\n");
    323 		if (random() % 6 == 1) {
    324 (void)printf("Your colorful comments awaken the wumpus!\n");
    325 			move_wump();
    326 			if (wumpus_loc == player_loc) {
    327 				wump_kill();
    328 				return(1);
    329 			}
    330 		}
    331 		return(0);
    332 	}
    333 
    334 	/* now let's move into that room and check it out for dangers */
    335 	if (next_room == room_num + 1)
    336 		jump(next_room = (random() % room_num) + 1);
    337 
    338 	player_loc = next_room;
    339 	for (;;) {
    340 		if (next_room == wumpus_loc) {		/* uh oh... */
    341 			wump_kill();
    342 			return(1);
    343 		}
    344 		if (cave[next_room].has_a_pit)
    345 			if (random() % 12 < 2) {
    346 				pit_survive();
    347 				return(0);
    348 			} else {
    349 				pit_kill();
    350 				return(1);
    351 			}
    352 
    353 		if (cave[next_room].has_a_bat) {
    354 			(void)printf(
    355 "*flap*  *flap*  *flap*  (humongous bats pick you up and move you%s!)\n",
    356 			    just_moved_by_bats ? " again": "");
    357 			next_room = player_loc = (random() % room_num) + 1;
    358 			just_moved_by_bats = 1;
    359 		}
    360 
    361 		else
    362 			break;
    363 	}
    364 	return(0);
    365 }
    366 
    367 shoot(room_list)
    368 	char *room_list;
    369 {
    370 	int chance, next, roomcnt;
    371 	int j, arrow_location, link, ok;
    372 	char *p, *strtok();
    373 
    374 	/*
    375 	 * Implement shooting arrows.  Arrows are shot by the player indicating
    376 	 * a space-separated list of rooms that the arrow should pass through;
    377 	 * if any of the rooms they specify are not accessible via tunnel from
    378 	 * the room the arrow is in, it will instead fly randomly into another
    379 	 * room.  If the player hits the wumpus, this routine will indicate
    380 	 * such.  If it misses, this routine will *move* the wumpus one room.
    381 	 * If it's the last arrow, the player then dies...  Returns 1 if the
    382 	 * player has won or died, 0 if nothing has happened.
    383 	 */
    384 	arrow_location = player_loc;
    385 	for (roomcnt = 1;; ++roomcnt, room_list = NULL) {
    386 		if (!(p = strtok(room_list, " \t\n")))
    387 			if (roomcnt == 1) {
    388 				(void)printf(
    389 			"The arrow falls to the ground at your feet!\n");
    390 				return(0);
    391 			} else
    392 				break;
    393 		if (roomcnt > 5) {
    394 			(void)printf(
    395 "The arrow wavers in its flight and and can go no further!\n");
    396 			break;
    397 		}
    398 		next = atoi(p);
    399 		for (j = 0, ok = 0; j < link_num; j++)
    400 			if (cave[arrow_location].tunnel[j] == next)
    401 				ok = 1;
    402 
    403 		if (ok) {
    404 			if (next > room_num) {
    405 				(void)printf(
    406 "A faint gleam tells you the arrow has gone through a magic tunnel!\n");
    407 				arrow_location = (random() % room_num) + 1;
    408 			} else
    409 				arrow_location = next;
    410 		} else {
    411 			link = (random() % link_num);
    412 			if (link == player_loc)
    413 				(void)printf(
    414 "*thunk*  The arrow can't find a way from %d to %d and flys back into\n\
    415 your room!\n",
    416 				    arrow_location, next);
    417 			else if (cave[arrow_location].tunnel[link] > room_num)
    418 				(void)printf(
    419 "*thunk*  The arrow flys randomly into a magic tunnel, thence into\n\
    420 room %d!\n",
    421 				    cave[arrow_location].tunnel[link]);
    422 			else
    423 				(void)printf(
    424 "*thunk*  The arrow can't find a way from %d to %d and flys randomly\n\
    425 into room %d!\n",
    426 				    arrow_location, next,
    427 				    cave[arrow_location].tunnel[link]);
    428 			arrow_location = cave[arrow_location].tunnel[link];
    429 			break;
    430 		}
    431 		chance = random() % 10;
    432 		if (roomcnt == 3 && chance < 2) {
    433 			(void)printf(
    434 "Your bowstring breaks!  *twaaaaaang*\n\
    435 The arrow is weakly shot and can go no further!\n");
    436 			break;
    437 		} else if (roomcnt == 4 && chance < 6) {
    438 			(void)printf(
    439 "The arrow wavers in its flight and and can go no further!\n");
    440 			break;
    441 		}
    442 	}
    443 
    444 	/*
    445 	 * now we've gotten into the new room let us see if El Wumpo is
    446 	 * in the same room ... if so we've a HIT and the player WON!
    447 	 */
    448 	if (arrow_location == wumpus_loc) {
    449 		kill_wump();
    450 		return(1);
    451 	}
    452 
    453 	if (arrow_location == player_loc) {
    454 		shoot_self();
    455 		return(1);
    456 	}
    457 
    458 	if (!--arrows_left) {
    459 		no_arrows();
    460 		return(1);
    461 	}
    462 
    463 	{
    464 		/* each time you shoot, it's more likely the wumpus moves */
    465 		static int lastchance = 2;
    466 
    467 		if (random() % level == EASY ? 12 : 9 < (lastchance += 2)) {
    468 			move_wump();
    469 			if (wumpus_loc == player_loc)
    470 				wump_kill();
    471 			lastchance = random() % 3;
    472 
    473 		}
    474 	}
    475 	return(0);
    476 }
    477 
    478 cave_init()
    479 {
    480 	register int i, j, k, link;
    481 	int delta, int_compare();
    482 	time_t time();
    483 
    484 	/*
    485 	 * This does most of the interesting work in this program actually!
    486 	 * In this routine we'll initialize the Wumpus cave to have all rooms
    487 	 * linking to all others by stepping through our data structure once,
    488 	 * recording all forward links and backwards links too.  The parallel
    489 	 * "linkcount" data structure ensures that no room ends up with more
    490 	 * than three links, regardless of the quality of the random number
    491 	 * generator that we're using.
    492 	 */
    493 	srandom((int)time((time_t *)0));
    494 
    495 	/* initialize the cave first off. */
    496 	for (i = 1; i <= room_num; ++i)
    497 		for (j = 0; j < link_num ; ++j)
    498 			cave[i].tunnel[j] = -1;
    499 
    500 	/* choose a random 'hop' delta for our guaranteed link */
    501 	while (!(delta = random() % room_num));
    502 
    503 	for (i = 1; i <= room_num; ++i) {
    504 		link = ((i + delta) % room_num) + 1;	/* connection */
    505 		cave[i].tunnel[0] = link;		/* forw link */
    506 		cave[link].tunnel[1] = i;		/* back link */
    507 	}
    508 	/* now fill in the rest of the cave with random connections */
    509 	for (i = 1; i <= room_num; i++)
    510 		for (j = 2; j < link_num ; j++) {
    511 			if (cave[i].tunnel[j] != -1)
    512 				continue;
    513 try_again:		link = (random() % room_num) + 1;
    514 			/* skip duplicates */
    515 			for (k = 0; k < j; k++)
    516 				if (cave[i].tunnel[k] == link)
    517 					goto try_again;
    518 			cave[i].tunnel[j] = link;
    519 			if (random() % 2 == 1)
    520 				continue;
    521 			for (k = 0; k < link_num; ++k) {
    522 				/* if duplicate, skip it */
    523 				if (cave[link].tunnel[k] == i)
    524 					k = link_num;
    525 
    526 				/* if open link, use it, force exit */
    527 				if (cave[link].tunnel[k] == -1) {
    528 					cave[link].tunnel[k] = i;
    529 					k = link_num;
    530 				}
    531 			}
    532 		}
    533 	/*
    534 	 * now that we're done, sort the tunnels in each of the rooms to
    535 	 * make it easier on the intrepid adventurer.
    536 	 */
    537 	for (i = 1; i <= room_num; ++i)
    538 		qsort(cave[i].tunnel, (u_int)link_num,
    539 		    sizeof(cave[i].tunnel[0]), int_compare);
    540 
    541 #ifdef DEBUG
    542 	if (debug)
    543 		for (i = 1; i <= room_num; ++i) {
    544 			(void)printf("<room %d  has tunnels to ", i);
    545 			for (j = 0; j < link_num; ++j)
    546 				(void)printf("%d ", cave[i].tunnel[j]);
    547 			(void)printf(">\n");
    548 		}
    549 #endif
    550 }
    551 
    552 clear_things_in_cave()
    553 {
    554 	register int i;
    555 
    556 	/*
    557 	 * remove bats and pits from the current cave in preparation for us
    558 	 * adding new ones via the initialize_things_in_cave() routines.
    559 	 */
    560 	for (i = 1; i <= room_num; ++i)
    561 		cave[i].has_a_bat = cave[i].has_a_pit = 0;
    562 }
    563 
    564 initialize_things_in_cave()
    565 {
    566 	register int i, loc;
    567 
    568 	/* place some bats, pits, the wumpus, and the player. */
    569 	for (i = 0; i < bat_num; ++i) {
    570 		do {
    571 			loc = (random() % room_num) + 1;
    572 		} while (cave[loc].has_a_bat);
    573 		cave[loc].has_a_bat = 1;
    574 #ifdef DEBUG
    575 		if (debug)
    576 			(void)printf("<bat in room %d>\n", loc);
    577 #endif
    578 	}
    579 
    580 	for (i = 0; i < pit_num; ++i) {
    581 		do {
    582 			loc = (random() % room_num) + 1;
    583 		} while (cave[loc].has_a_pit && cave[loc].has_a_bat);
    584 		cave[loc].has_a_pit = 1;
    585 #ifdef DEBUG
    586 		if (debug)
    587 			(void)printf("<pit in room %d>\n", loc);
    588 #endif
    589 	}
    590 
    591 	wumpus_loc = (random() % room_num) + 1;
    592 #ifdef DEBUG
    593 	if (debug)
    594 		(void)printf("<wumpus in room %d>\n", loc);
    595 #endif
    596 
    597 	do {
    598 		player_loc = (random() % room_num) + 1;
    599 	} while (player_loc == wumpus_loc || (level == HARD ?
    600 	    (link_num / room_num < 0.4 ? wump_nearby() : 0) : 0));
    601 }
    602 
    603 getans(prompt)
    604 	char *prompt;
    605 {
    606 	char buf[20];
    607 
    608 	/*
    609 	 * simple routine to ask the yes/no question specified until the user
    610 	 * answers yes or no, then return 1 if they said 'yes' and 0 if they
    611 	 * answered 'no'.
    612 	 */
    613 	for (;;) {
    614 		(void)printf("%s", prompt);
    615 		(void)fflush(stdout);
    616 		if (!fgets(buf, sizeof(buf), stdin))
    617 			return(0);
    618 		if (*buf == 'N' || *buf == 'n')
    619 			return(0);
    620 		if (*buf == 'Y' || *buf == 'y')
    621 			return(1);
    622 		(void)printf(
    623 "I don't understand your answer; please enter 'y' or 'n'!\n");
    624 	}
    625 	/* NOTREACHED */
    626 }
    627 
    628 bats_nearby()
    629 {
    630 	register int i;
    631 
    632 	/* check for bats in the immediate vicinity */
    633 	for (i = 0; i < link_num; ++i)
    634 		if (cave[cave[player_loc].tunnel[i]].has_a_bat)
    635 			return(1);
    636 	return(0);
    637 }
    638 
    639 pit_nearby()
    640 {
    641 	register int i;
    642 
    643 	/* check for pits in the immediate vicinity */
    644 	for (i = 0; i < link_num; ++i)
    645 		if (cave[cave[player_loc].tunnel[i]].has_a_pit)
    646 			return(1);
    647 	return(0);
    648 }
    649 
    650 wump_nearby()
    651 {
    652 	register int i, j;
    653 
    654 	/* check for a wumpus within TWO caves of where we are */
    655 	for (i = 0; i < link_num; ++i) {
    656 		if (cave[player_loc].tunnel[i] == wumpus_loc)
    657 			return(1);
    658 		for (j = 0; j < link_num; ++j)
    659 			if (cave[cave[player_loc].tunnel[i]].tunnel[j] ==
    660 			    wumpus_loc)
    661 				return(1);
    662 	}
    663 	return(0);
    664 }
    665 
    666 move_wump()
    667 {
    668 	wumpus_loc = cave[wumpus_loc].tunnel[random() % link_num];
    669 }
    670 
    671 int_compare(a, b)
    672 	int *a, *b;
    673 {
    674 	return(*a < *b ? -1 : 1);
    675 }
    676 
    677 instructions()
    678 {
    679 	char buf[120], *p, *getenv();
    680 
    681 	/*
    682 	 * read the instructions file, if needed, and show the user how to
    683 	 * play this game!
    684 	 */
    685 	if (!getans("Instructions? (y-n) "))
    686 		return;
    687 
    688 	if (access(_PATH_WUMPINFO, R_OK)) {
    689 		(void)printf(
    690 "Sorry, but the instruction file seems to have disappeared in a\n\
    691 puff of greasy black smoke! (poof)\n");
    692 		return;
    693 	}
    694 
    695 	if (!(p = getenv("PAGER")) ||
    696 	    strlen(p) > sizeof(buf) + strlen(_PATH_WUMPINFO) + 5)
    697 		p = _PATH_PAGER;
    698 
    699 	(void)sprintf(buf, "%s %s", p, _PATH_WUMPINFO);
    700 	(void)system(buf);
    701 }
    702 
    703 usage()
    704 {
    705 	(void)fprintf(stderr,
    706 "usage: wump [-h] [-a arrows] [-b bats] [-p pits] [-r rooms] [-t tunnels]\n");
    707 	exit(1);
    708 }
    709 
    710 /* messages */
    711 
    712 wump_kill()
    713 {
    714 	(void)printf(
    715 "*ROAR* *chomp* *snurfle* *chomp*!\n\
    716 Much to the delight of the Wumpus, you walked right into his mouth,\n\
    717 making you one of the easiest dinners he's ever had!  For you, however,\n\
    718 it's a rather unpleasant death.  The only good thing is that it's been\n\
    719 so long since the evil Wumpus cleaned his teeth that you immediately\n\
    720 passed out from the stench!\n");
    721 }
    722 
    723 kill_wump()
    724 {
    725 	(void)printf(
    726 "*thwock!* *groan* *crash*\n\n\
    727 A horrible roar fills the cave, and you realize, with a smile, that you\n\
    728 have slain the evil Wumpus and won the game!  You don't want to tarry for\n\
    729 long, however, because not only is the Wumpus famous, but the stench of\n\
    730 dead Wumpus is also quite well known, a stench plenty enough to slay the\n\
    731 mightiest adventurer at a single whiff!!\n");
    732 }
    733 
    734 no_arrows()
    735 {
    736 	(void)printf(
    737 "\nYou turn and look at your quiver, and realize with a sinking feeling\n\
    738 that you've just shot your last arrow (figuratively, too).  Sensing this\n\
    739 with its psychic powers, the evil Wumpus rampagees through the cave, finds\n\
    740 you, and with a mighty *ROAR* eats you alive!\n");
    741 }
    742 
    743 shoot_self()
    744 {
    745 	(void)printf(
    746 "\n*Thwack!*  A sudden piercing feeling informs you that the ricochet\n\
    747 of your wild arrow has resulted in it wedging in your side, causing\n\
    748 extreme agony.  The evil Wumpus, with its psychic powers, realizes this\n\
    749 and immediately rushes to your side, not to help, alas, but to EAT YOU!\n\
    750 (*CHOMP*)\n");
    751 }
    752 
    753 jump(where)
    754 	int where;
    755 {
    756 	(void)printf(
    757 "\nWith a jaunty step you enter the magic tunnel.  As you do, you\n\
    758 notice that the walls are shimmering and glowing.  Suddenly you feel\n\
    759 a very curious, warm sensation and find yourself in room %d!!\n", where);
    760 }
    761 
    762 pit_kill()
    763 {
    764 	(void)printf(
    765 "*AAAUUUUGGGGGHHHHHhhhhhhhhhh...*\n\
    766 The whistling sound and updraft as you walked into this room of the\n\
    767 cave apparently wasn't enough to clue you in to the presence of the\n\
    768 bottomless pit.  You have a lot of time to reflect on this error as\n\
    769 you fall many miles to the core of the earth.  Look on the bright side;\n\
    770 you can at least find out if Jules Verne was right...\n");
    771 }
    772 
    773 pit_survive()
    774 {
    775 	(void)printf(
    776 "Without conscious thought you grab for the side of the cave and manage\n\
    777 to grasp onto a rocky outcrop.  Beneath your feet stretches the limitless\n\
    778 depths of a bottomless pit!  Rock crumbles beneath your feet!\n");
    779 }
    780