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