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