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
13 * SPDX-FileCopyrightText: (C) Eric S. Raymond <esr@thyrsus.com>
20 #include <sys/socket.h>
25 static int j, k, scratchloc, pies;
26 static char inp[BUFSIZ]; /* common input buffer */
28 #define NUMBERS "0123456789"
51 static int cave[20][3] = {
52 {1, 4, 7}, {0, 2, 9}, {1, 3, 11}, {2, 4, 13}, {0, 3, 5},
53 {4, 6, 14}, {5, 7, 16}, {0, 6, 8}, {7, 9, 17}, {1, 8, 10},
54 {9, 11, 18}, {2, 10, 12}, {11, 13, 19}, {3, 12, 14}, {5, 13, 15},
55 {14, 16, 19}, {6, 15, 17}, {8, 16, 18}, {10, 17, 19}, {12, 15, 18},
58 #define FNA() (rand() % 20)
60 #define FNB() (rand() % 3)
62 #define FNC() (rand() % 4)
67 (void)printf("%s? ", prompt);
68 if (fgets(inp, sizeof(inp), stdin)) {
69 return (tolower(inp[0]));
76 #define PM(x) puts(x);
78 void print_instructions() {
79 PM("Welcome to `Hunt the Superhack'\n")
81 PM(" The superhack lives on the 9th floor of 45 Technology Square "
83 PM("Cambridge, Massachusetts. Your mission is to throw a pie in his "
86 PM(" First, you'll have to find him. A botched experiment by an "
88 PM("physics group has regularized the floor's topology, so that each");
89 PM("room has exits to three other rooms. (Look at a dodecahedron to");
90 PM("see how this works --- if you don't know what a dodecahedron is,");
91 PM("ask someone.)\n");
94 PM(" Each turn you may move to an adjacent room or throw a pie. If");
95 PM("you run out of pies, you lose. Each pie can pass through up to");
96 PM("five rooms (connected by a continuous path from where you are). "
98 PM("aim by telling the computer which rooms you want to throw "
100 PM("If the path is incorrect (presumes a nonexistent connection) the ");
101 PM("pie moves at random.");
103 PM(" If a pie hits the superhack, you win. If it hits you, you "
106 (void)fputs("<Press return to continue>", stdout);
107 IGNORE(fgets(inp, sizeof(inp), stdin));
111 PM(" Starlets --- two rooms contain lonely, beautiful women. If "
113 PM("enter these, you will become fascinated and forget your mission "
115 PM("you engage in futile efforts to pick one up. You weenie.");
116 PM(" Droids --- two rooms are guarded by experimental AI security ");
117 PM("droids. If you enter either, the droid will grab you and hustle");
118 PM("you off to somewhere else, at random.");
119 PM(" Lusers --- two rooms contain hungry lusers. If you blunder "
121 PM("either, they will eat one of your pies.");
122 PM(" Superhack --- the superhack is not bothered by hazards (the");
123 PM("lusers are in awe of him, he's programmed the droids to ignore "
125 PM("and he has no sex life). Usually he is hacking. Two things can");
126 PM("interrupt him; you throwing a pie or you entering his room.\n");
127 PM(" On an interrupt, the superhack moves (3/4 chance) or stays "
129 PM("he is (1/4 chance). After that, if he is where you are, he "
131 PM("you and you lose!\n");
133 (void)fputs("<Press return to continue>", stdout);
134 (void)fgets(inp, sizeof(inp), stdin);
138 PM(" When you are one room away from the superhack or a hazard,");
139 PM("the computer says:");
140 PM(" superhack: \"I smell a superhack!\"");
141 PM(" security droid: \"Droids nearby!\"");
142 PM(" starlet: \"I smell perfume!\"");
143 PM(" luser: \"Lusers nearby!\"");
145 PM("If you take too long finding the superhack, hazards may move. "
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. "
159 PM("other than one of these commands displays a short help message.");
162 void move_hazard(where) int where;
168 for (j = 0; j < LOCS; j++) {
169 if (loc[j] == newloc) {
177 void check_hazards() {
178 /* basic status report */
179 (void)printf("You are in room %d. Exits lead to %d, %d, %d. You have "
181 loc[YOU] + 1, cave[loc[YOU]][0] + 1, cave[loc[YOU]][1] + 1,
182 cave[loc[YOU]][2] + 1, pies);
184 /* maybe it's migration time */
189 PM("Swish, swish, swish --- starlets are moving!");
190 move_hazard(STARLET1);
191 move_hazard(STARLET2);
196 PM("Clank, clank, clank --- droids are moving!");
203 PM("Grumble, grumble, grumble --- lusers are moving!");
209 /* display hazard warnings */
210 for (k = 0; k < 3; k++) {
211 int room = cave[loc[YOU]][k];
213 if (room == loc[RMS]) {
214 (void)puts("I smell a superhack!");
215 } else if (room == loc[STARLET1] || room == loc[STARLET2]) {
216 (void)puts("I smell perfume!");
217 } else if (room == loc[DROID1] || room == loc[DROID2]) {
218 (void)puts("Droids nearby!");
219 } else if (room == loc[LUSER1] || room == loc[LUSER2]) {
220 (void)puts("Lusers nearby!");
226 extern void check_shot(), move_superhack();
229 j9 = sscanf(inp + strcspn(inp, NUMBERS), "%d %d %d %d %d", &path[0],
230 &path[1], &path[2], &path[3], &path[4]);
233 PM("Sorry, I didn't see any room numbers after your throw "
238 for (k = 0; k < j9; k++) {
239 if (k >= 2 && path[k] == path[k - 2]) {
241 "Pies can't fly that crookedly --- try again.");
246 scratchloc = loc[YOU];
248 for (k = 0; k < j9; k++) {
251 for (k1 = 0; k1 < 3; k1++) {
252 if (cave[scratchloc][k1] == path[k]) {
253 scratchloc = path[k];
255 if (finished != NOT) {
261 scratchloc = cave[scratchloc][FNB()];
266 if (finished == NOT) {
267 (void)puts("You missed.");
269 scratchloc = loc[YOU];
280 if (scratchloc == loc[RMS]) {
281 (void)puts("Splat! You got the superhack! You win.");
285 else if (scratchloc == loc[YOU]) {
286 (void)puts("Ugh! The pie hit you! You lose.");
291 void move_superhack() {
295 loc[RMS] = cave[loc[RMS]][k];
298 if (loc[RMS] != loc[YOU]) {
302 (void)puts("The superhack flames you to a crisp. You lose!");
308 if (sscanf(inp + strcspn(inp, NUMBERS), "%d", &scratchloc) < 1) {
309 PM("Sorry, I didn't see a room number after your `m' command.");
315 for (k = 0; k < 3; k++) {
316 if (cave[loc[YOU]][k] == scratchloc) {
321 PM("You can't get there from here!");
325 loc[YOU] = scratchloc;
327 if (scratchloc == loc[RMS]) {
328 PM("Yow! You interrupted the superhack.");
330 } else if (scratchloc == loc[STARLET1] || scratchloc == loc[STARLET2]) {
331 PM("You begin to babble at an unimpressed starlet. You lose!");
333 } else if (scratchloc == loc[DROID1] || scratchloc == loc[DROID2]) {
334 PM("Zap --- security droid snatch. Elsewheresville for you!");
335 scratchloc = loc[YOU] = FNA();
337 } else if (scratchloc == loc[LUSER1] || scratchloc == loc[LUSER2]) {
338 PM("Munch --- lusers ate one of your pies!");
343 int main(int argc, char *argv[]) {
344 if (argc >= 2 && strcmp(argv[1], "-s") == 0) {
345 srand(atoi(argv[2]));
347 srand((int)time((long *)0));
352 for (j = 0; j < LOCS; j++) {
356 for (j = 0; j < LOCS; j++) {
357 for (k = 0; k < LOCS; k++) {
360 } else if (loc[j] == loc[k]) {
366 (void)puts("Hunt the Superhack");
369 scratchloc = loc[YOU];
372 while (finished == NOT) {
377 c = getlet("Throw, move or help [t,m,?]");
381 } else if (c == 'm') {
383 } else if (c == '?') {
384 print_instructions();
388 (void)printf("RMS is at %d, starlets at %d/%d, "
389 "droids %d/%d, lusers %d/%d\n",
390 loc[RMS] + 1, loc[STARLET1] + 1,
391 loc[STARLET2] + 1, loc[DROID1] + 1,
392 loc[DROID2] + 1, loc[LUSER1] + 1,
397 PM("Available commands are:\n");
398 PM(" ? --- print long "
400 PM(" m <number> --- move to room with given "
402 PM(" t <numbers> --- throw through given "
405 PM(" d --- dump hazard locations.");
407 PM("The list of room numbers after t must be "
414 if (getlet("Play again") != 'y') {
415 PM("Happy hacking!");
422 /* superhack.c ends here */