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