2 * superhack.c --- modern version of a classic adventure game
4 * Author: Eric S. Raymond <esr@snark.thyrsus.com>
6 * My update of a classic adventure game. This code is no relation to
7 * the elaborate dungeon game called `Hack'.
9 * Any resemblance to persons living or dead is strictly coincidental. And
10 * if you believe *that*...
12 * SPDX-License-Identifier: BSD-2-Clause
21 #include <sys/socket.h>
24 static int j, k, scratchloc, pies;
25 static char inp[BUFSIZ]; /* common input buffer */
27 #define NUMBERS "0123456789"
44 #define IGNORE(r) do{if(r);}while(0)
46 static int cave[20][3] =
70 #define FNA() (rand() % 20)
72 #define FNB() (rand() % 3)
74 #define FNC() (rand() % 4)
79 (void) printf("%s? ", prompt);
80 if (fgets(inp, sizeof(inp), stdin))
81 return(tolower(inp[0]));
88 #define PM(x) puts(x);
90 void print_instructions()
92 PM("Welcome to `Hunt the Superhack'\n")
94 PM(" The superhack lives on the 9th floor of 45 Technology Square in");
95 PM("Cambridge, Massachusetts. Your mission is to throw a pie in his face.\n");
97 PM(" First, you'll have to find him. A botched experiment by an MIT");
98 PM("physics group has regularized the floor's topology, so that each");
99 PM("room has exits to three other rooms. (Look at a dodecahedron to");
100 PM("see how this works --- if you don't know what a dodecahedron is,");
101 PM("ask someone.)\n");
104 PM(" Each turn you may move to an adjacent room or throw a pie. If");
105 PM("you run out of pies, you lose. Each pie can pass through up to");
106 PM("five rooms (connected by a continuous path from where you are). You");
107 PM("aim by telling the computer which rooms you want to throw through.");
108 PM("If the path is incorrect (presumes a nonexistent connection) the ");
109 PM("pie moves at random.");
111 PM(" If a pie hits the superhack, you win. If it hits you, you lose!\n");
113 (void) fputs("<Press return to continue>", stdout);
114 IGNORE(fgets(inp, sizeof(inp), stdin));
115 (void) putchar('\n');
118 PM(" Starlets --- two rooms contain lonely, beautiful women. If you");
119 PM("enter these, you will become fascinated and forget your mission as");
120 PM("you engage in futile efforts to pick one up. You weenie.");
121 PM(" Droids --- two rooms are guarded by experimental AI security ");
122 PM("droids. If you enter either, the droid will grab you and hustle");
123 PM("you off to somewhere else, at random.");
124 PM(" Lusers --- two rooms contain hungry lusers. If you blunder into");
125 PM("either, they will eat one of your pies.");
126 PM(" Superhack --- the superhack is not bothered by hazards (the");
127 PM("lusers are in awe of him, he's programmed the droids to ignore him,");
128 PM("and he has no sex life). Usually he is hacking. Two things can");
129 PM("interrupt him; you throwing a pie or you entering his room.\n");
130 PM(" On an interrupt, the superhack moves (3/4 chance) or stays where");
131 PM("he is (1/4 chance). After that, if he is where you are, he flames");
132 PM("you and you lose!\n");
134 (void) fputs("<Press return to continue>", stdout);
135 (void) fgets(inp, sizeof(inp), stdin);
136 (void) putchar('\n');
139 PM(" When you are one room away from the superhack or a hazard,");
140 PM("the computer says:");
141 PM(" superhack: \"I smell a superhack!\"");
142 PM(" security droid: \"Droids nearby!\"");
143 PM(" starlet: \"I smell perfume!\"");
144 PM(" luser: \"Lusers nearby!\"");
146 PM("If you take too long finding the superhack, hazards may move. You");
147 PM("will get a warning when this happens.\n");
150 PM(" Available commands are:\n");
151 PM(" ? --- print long instructions.");
152 PM(" m <number> --- move to room with given number.");
153 PM(" t <numbers> --- throw through given rooms.");
155 PM(" d --- dump hazard locations.");
157 PM("\nThe list of room numbers after t must be space-separated. Anything");
158 PM("other than one of these commands displays a short help message.");
161 void move_hazard(where)
168 for (j = 0; j < LOCS; j++)
169 if (loc[j] == newloc)
177 /* basic status report */
178 (void) printf("You are in room %d. Exits lead to %d, %d, %d. You have %d pies left.\n",
185 /* maybe it's migration time */
191 PM("Swish, swish, swish --- starlets are moving!");
192 move_hazard(STARLET1);
193 move_hazard(STARLET2);
198 PM("Clank, clank, clank --- droids are moving!");
205 PM("Grumble, grumble, grumble --- lusers are moving!");
211 /* display hazard warnings */
212 for (k = 0; k < 3; k++)
214 int room = cave[loc[YOU]][k];
216 if (room == loc[RMS])
217 (void) puts("I smell a superhack!");
218 else if (room == loc[STARLET1] || room == loc[STARLET2])
219 (void) puts("I smell perfume!");
220 else if (room == loc[DROID1] || room == loc[DROID2])
221 (void) puts("Droids nearby!");
222 else if (room == loc[LUSER1] || room == loc[LUSER2])
223 (void) puts("Lusers nearby!");
229 extern void check_shot(), move_superhack();
232 j9 = sscanf(inp + strcspn(inp, NUMBERS), "%d %d %d %d %d",
233 &path[0], &path[1], &path[2], &path[3], &path[4]);
237 PM("Sorry, I didn't see any room numbers after your throw command.");
241 for (k = 0; k < j9; k++)
242 if (k >= 2 && path[k] == path[k - 2])
244 (void) puts("Pies can't fly that crookedly --- try again.");
248 scratchloc = loc[YOU];
250 for (k = 0; k < j9; k++)
254 for (k1 = 0; k1 < 3; k1++)
256 if (cave[scratchloc][k1] == path[k])
258 scratchloc = path[k];
266 scratchloc = cave[scratchloc][FNB()];
274 (void) puts("You missed.");
276 scratchloc = loc[YOU];
288 if (scratchloc == loc[RMS])
290 (void) puts("Splat! You got the superhack! You win.");
294 else if (scratchloc == loc[YOU])
296 (void) puts("Ugh! The pie hit you! You lose.");
301 void move_superhack()
306 loc[RMS] = cave[loc[RMS]][k];
308 if (loc[RMS] != loc[YOU])
311 (void) puts("The superhack flames you to a crisp. You lose!");
319 if (sscanf(inp + strcspn(inp, NUMBERS), "%d", &scratchloc) < 1)
321 PM("Sorry, I didn't see a room number after your `m' command.");
327 for (k = 0; k < 3; k++)
328 if (cave[loc[YOU]][k] == scratchloc)
331 PM("You can't get there from here!");
335 loc[YOU] = scratchloc;
337 if (scratchloc == loc[RMS])
339 PM("Yow! You interrupted the superhack.");
342 else if (scratchloc == loc[STARLET1] || scratchloc == loc[STARLET2])
344 PM("You begin to babble at an unimpressed starlet. You lose!");
347 else if (scratchloc == loc[DROID1] || scratchloc == loc[DROID2])
349 PM("Zap --- security droid snatch. Elsewheresville for you!");
350 scratchloc = loc[YOU] = FNA();
353 else if (scratchloc == loc[LUSER1] || scratchloc == loc[LUSER2])
355 PM("Munch --- lusers ate one of your pies!");
360 int main(int argc, char *argv[])
362 if (argc >= 2 && strcmp(argv[1], "-s") == 0)
363 srand(atoi(argv[2]));
365 srand((int)time((long *) 0));
370 for (j = 0; j < LOCS; j++)
373 for (j = 0; j < LOCS; j++)
374 for (k = 0; k < LOCS; k++)
377 else if (loc[j] == loc[k])
380 (void) puts("Hunt the Superhack");
383 scratchloc = loc[YOU];
386 while (finished == NOT)
392 c = getlet("Throw, move or help [t,m,?]");
399 print_instructions();
403 (void) printf("RMS is at %d, starlets at %d/%d, droids %d/%d, lusers %d/%d\n",
405 loc[STARLET1] + 1, loc[STARLET2] + 1,
406 loc[DROID1] + 1, loc[DROID2] + 1,
407 loc[LUSER1] + 1, loc[LUSER2] + 1);
412 PM("Available commands are:\n");
413 PM(" ? --- print long instructions.");
414 PM(" m <number> --- move to room with given number.");
415 PM(" t <numbers> --- throw through given rooms.");
417 PM(" d --- dump hazard locations.");
419 PM("The list of room numbers after t must be space-separated");
422 (void) putchar('\n');
425 if (getlet("Play again") != 'y')
427 PM("Happy hacking!");
434 /* superhack.c ends here */