]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - hack/hack.main.c
introduce some common variables for use in GCC warning disables:
[bsdgames-darwin.git] / hack / hack.main.c
1 /* $NetBSD: hack.main.c,v 1.17 2011/08/06 20:42:43 dholland Exp $ */
2
3 /*
4 * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
5 * Amsterdam
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * - Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 *
15 * - Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * - Neither the name of the Stichting Centrum voor Wiskunde en
20 * Informatica, nor the names of its contributors may be used to endorse or
21 * promote products derived from this software without specific prior
22 * written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
25 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
27 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
28 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36
37 /*
38 * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
39 * All rights reserved.
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * 3. The name of the author may not be used to endorse or promote products
50 * derived from this software without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
53 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
54 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
55 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
56 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
57 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
58 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
59 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
60 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
61 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62 */
63
64 #include <sys/cdefs.h>
65 #ifndef lint
66 __RCSID("$NetBSD: hack.main.c,v 1.17 2011/08/06 20:42:43 dholland Exp $");
67 #endif /* not lint */
68
69 #include <signal.h>
70 #include <stdlib.h>
71 #include <unistd.h>
72 #include <fcntl.h>
73 #include "hack.h"
74 #include "extern.h"
75
76 #ifdef QUEST
77 #define gamename "quest"
78 #else
79 #define gamename "hack"
80 #endif
81
82 int (*afternmv)(void);
83 int (*occupation)(void);
84 const char *occtxt; /* defined when occupation != NULL */
85
86 int hackpid; /* current pid */
87 int locknum; /* max num of players */
88 #ifdef DEF_PAGER
89 const char *catmore; /* default pager */
90 #endif
91 char SAVEF[PL_NSIZ + 11] = "save/"; /* save/99999player */
92 char *hname; /* name of the game (argv[0] of call) */
93
94 static char obuf[BUFSIZ]; /* BUFSIZ is defined in stdio.h */
95
96 int main(int, char *[]);
97 static void chdirx(const char *, boolean);
98
99 int
100 main(int argc, char *argv[])
101 {
102 int fd;
103 #ifdef CHDIR
104 char *dir;
105 #endif
106
107 /* Check for dirty tricks with closed fds 0, 1, 2 */
108 fd = open("/dev/null", O_RDONLY);
109 if (fd < 3)
110 exit(1);
111 close(fd);
112
113 hname = argv[0];
114 hackpid = getpid();
115
116 #ifdef CHDIR /* otherwise no chdir() */
117 /*
118 * See if we must change directory to the playground.
119 * (Perhaps hack runs suid and playground is inaccessible
120 * for the player.)
121 * The environment variable HACKDIR is overridden by a
122 * -d command line option (must be the first option given)
123 */
124
125 dir = getenv("HACKDIR");
126 if (argc > 1 && !strncmp(argv[1], "-d", 2)) {
127 argc--;
128 argv++;
129 dir = argv[0] + 2;
130 if (*dir == '=' || *dir == ':')
131 dir++;
132 if (!*dir && argc > 1) {
133 argc--;
134 argv++;
135 dir = argv[0];
136 }
137 if (!*dir)
138 error("Flag -d must be followed by a directory name.");
139 }
140 #endif
141
142 /*
143 * Who am i? Algorithm: 1. Use name as specified in HACKOPTIONS
144 * 2. Use $USER or $LOGNAME (if 1. fails)
145 * 3. Use getlogin() (if 2. fails)
146 * The resulting name is overridden by command line options.
147 * If everything fails, or if the resulting name is some generic
148 * account like "games", "play", "player", "hack" then eventually
149 * we'll ask him.
150 * Note that we trust him here; it is possible to play under
151 * somebody else's name.
152 */
153 {
154 char *s;
155
156 initoptions();
157 if (!*plname && (s = getenv("USER")))
158 (void) strncpy(plname, s, sizeof(plname) - 1);
159 if (!*plname && (s = getenv("LOGNAME")))
160 (void) strncpy(plname, s, sizeof(plname) - 1);
161 if (!*plname && (s = getlogin()))
162 (void) strncpy(plname, s, sizeof(plname) - 1);
163 }
164
165 /*
166 * Now we know the directory containing 'record' and
167 * may do a prscore().
168 */
169 if (argc > 1 && !strncmp(argv[1], "-s", 2)) {
170 #ifdef CHDIR
171 chdirx(dir, 0);
172 #endif
173 prscore(argc, argv);
174 exit(0);
175 }
176 /*
177 * It seems he really wants to play.
178 * Remember tty modes, to be restored on exit.
179 */
180 gettty();
181 setbuf(stdout, obuf);
182 setrandom();
183 startup();
184 cls();
185 u.uhp = 1; /* prevent RIP on early quits */
186 u.ux = FAR; /* prevent nscr() */
187 (void) signal(SIGHUP, hang_up);
188
189 /*
190 * Find the creation date of this game,
191 * so as to avoid restoring outdated savefiles.
192 */
193 gethdate(hname);
194
195 /*
196 * We cannot do chdir earlier, otherwise gethdate will fail.
197 */
198 #ifdef CHDIR
199 chdirx(dir, 1);
200 #endif
201
202 /*
203 * Process options.
204 */
205 while (argc > 1 && argv[1][0] == '-') {
206 argv++;
207 argc--;
208 switch (argv[0][1]) {
209 #ifdef WIZARD
210 case 'D':
211 /* if(!strcmp(getlogin(), WIZARD)) */
212 wizard = TRUE;
213 /*
214 * else printf("Sorry.\n");
215 */
216 break;
217 #endif
218 #ifdef NEWS
219 case 'n':
220 flags.nonews = TRUE;
221 break;
222 #endif
223 case 'u':
224 if (argv[0][2])
225 (void) strncpy(plname, argv[0] + 2, sizeof(plname) - 1);
226 else if (argc > 1) {
227 argc--;
228 argv++;
229 (void) strncpy(plname, argv[0], sizeof(plname) - 1);
230 } else
231 printf("Player name expected after -u\n");
232 break;
233 default:
234 /* allow -T for Tourist, etc. */
235 (void) strncpy(pl_character, argv[0] + 1,
236 sizeof(pl_character) - 1);
237
238 /* printf("Unknown option: %s\n", *argv); */
239 }
240 }
241
242 if (argc > 1)
243 locknum = atoi(argv[1]);
244 #ifdef MAX_NR_OF_PLAYERS
245 if (!locknum || locknum > MAX_NR_OF_PLAYERS)
246 locknum = MAX_NR_OF_PLAYERS;
247 #endif
248 #ifdef DEF_PAGER
249 if (((catmore = getenv("HACKPAGER")) == NULL &&
250 (catmore = getenv("PAGER")) == NULL) ||
251 catmore[0] == '\0')
252 catmore = DEF_PAGER;
253 #endif
254 #ifdef MAIL
255 getmailstatus();
256 #endif
257 #ifdef WIZARD
258 if (wizard)
259 (void) strcpy(plname, "wizard");
260 else
261 #endif
262 if (!*plname || !strncmp(plname, "player", 4)
263 || !strncmp(plname, "games", 4))
264 askname();
265 plnamesuffix(); /* strip suffix from name; calls askname() */
266 /* again if suffix was whole name */
267 /* accepts any suffix */
268 #ifdef WIZARD
269 if (!wizard) {
270 #endif
271 /*
272 * check for multiple games under the same name
273 * (if !locknum) or check max nr of players (otherwise)
274 */
275 (void) signal(SIGQUIT, SIG_IGN);
276 (void) signal(SIGINT, SIG_IGN);
277 if (!locknum)
278 (void) strcpy(lock, plname);
279 getlock(); /* sets lock if locknum != 0 */
280 #ifdef WIZARD
281 } else {
282 char *sfoo;
283 (void) strcpy(lock, plname);
284 if ((sfoo = getenv("MAGIC")) != NULL)
285 while (*sfoo) {
286 switch (*sfoo++) {
287 case 'n':
288 (void) srandom(*sfoo++);
289 break;
290 }
291 }
292 if ((sfoo = getenv("GENOCIDED")) != NULL) {
293 if (*sfoo == '!') {
294 const struct permonst *pm = mons;
295 char *gp = genocided;
296
297 while (pm < mons + CMNUM + 2) {
298 if (!strchr(sfoo, pm->mlet))
299 *gp++ = pm->mlet;
300 pm++;
301 }
302 *gp = 0;
303 } else
304 (void) strlcpy(genocided, sfoo,
305 sizeof(genocided));
306 (void) strcpy(fut_geno, genocided);
307 }
308 }
309 #endif
310 setftty();
311 (void) snprintf(SAVEF, sizeof(SAVEF), "save/%d%s", getuid(), plname);
312 regularize(SAVEF + 5); /* avoid . or / in name */
313 if ((fd = open(SAVEF, O_RDONLY)) >= 0 &&
314 (uptodate(fd) || unlink(SAVEF) == 666)) {
315 (void) signal(SIGINT, done1);
316 pline("Restoring old save file...");
317 (void) fflush(stdout);
318 if (!dorecover(fd))
319 goto not_recovered;
320 pline("Hello %s, welcome to %s!", plname, gamename);
321 flags.move = 0;
322 } else {
323 not_recovered:
324 fobj = fcobj = invent = 0;
325 fmon = fallen_down = 0;
326 ftrap = 0;
327 fgold = 0;
328 flags.ident = 1;
329 init_objects();
330 u_init();
331
332 (void) signal(SIGINT, done1);
333 mklev();
334 u.ux = xupstair;
335 u.uy = yupstair;
336 (void) inshop();
337 setsee();
338 flags.botlx = 1;
339 makedog();
340 {
341 struct monst *mtmp;
342 if ((mtmp = m_at(u.ux, u.uy)) != NULL)
343 mnexto(mtmp); /* riv05!a3 */
344 }
345 seemons();
346 #ifdef NEWS
347 if (flags.nonews || !readnews())
348 /* after reading news we did docrt() already */
349 #endif
350 docrt();
351
352 /* give welcome message before pickup messages */
353 pline("Hello %s, welcome to %s!", plname, gamename);
354
355 pickup(1);
356 read_engr_at(u.ux, u.uy);
357 flags.move = 1;
358 }
359
360 flags.moonphase = phase_of_the_moon();
361 if (flags.moonphase == FULL_MOON) {
362 pline("You are lucky! Full moon tonight.");
363 u.uluck++;
364 } else if (flags.moonphase == NEW_MOON) {
365 pline("Be careful! New moon tonight.");
366 }
367 initrack();
368
369 for (;;) {
370 if (flags.move) { /* actual time passed */
371
372 settrack();
373
374 if (moves % 2 == 0 ||
375 (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) {
376 movemon();
377 if (!rn2(70))
378 (void) makemon((struct permonst *) 0, 0, 0);
379 }
380 if (Glib)
381 glibr();
382 timeout();
383 ++moves;
384 if (flags.time)
385 flags.botl = 1;
386 if (u.uhp < 1) {
387 pline("You die...");
388 done("died");
389 }
390 if (u.uhp * 10 < u.uhpmax && moves - wailmsg > 50) {
391 wailmsg = moves;
392 if (u.uhp == 1)
393 pline("You hear the wailing of the Banshee...");
394 else
395 pline("You hear the howling of the CwnAnnwn...");
396 }
397 if (u.uhp < u.uhpmax) {
398 if (u.ulevel > 9) {
399 if (Regeneration || !(moves % 3)) {
400 flags.botl = 1;
401 u.uhp += rnd((int) u.ulevel - 9);
402 if (u.uhp > u.uhpmax)
403 u.uhp = u.uhpmax;
404 }
405 } else if (Regeneration ||
406 (!(moves % (22 - u.ulevel * 2)))) {
407 flags.botl = 1;
408 u.uhp++;
409 }
410 }
411 if (Teleportation && !rn2(85))
412 tele();
413 if (Searching && multi >= 0)
414 (void) dosearch();
415 gethungry();
416 invault();
417 amulet();
418 }
419 if (multi < 0) {
420 if (!++multi) {
421 if (nomovemsg)
422 pline("%s", nomovemsg);
423 else
424 pline("You can move again.");
425 nomovemsg = 0;
426 if (afternmv)
427 (*afternmv) ();
428 afternmv = 0;
429 }
430 }
431 find_ac();
432 #ifndef QUEST
433 if (!flags.mv || Blind)
434 #endif
435 {
436 seeobjs();
437 seemons();
438 nscr();
439 }
440 if (flags.botl || flags.botlx)
441 bot();
442
443 flags.move = 1;
444
445 if (multi >= 0 && occupation) {
446 if (monster_nearby())
447 stop_occupation();
448 else if ((*occupation) () == 0)
449 occupation = 0;
450 continue;
451 }
452 if (multi > 0) {
453 #ifdef QUEST
454 if (flags.run >= 4)
455 finddir();
456 #endif
457 lookaround();
458 if (!multi) { /* lookaround may clear multi */
459 flags.move = 0;
460 continue;
461 }
462 if (flags.mv) {
463 if (multi < COLNO && !--multi)
464 flags.mv = flags.run = 0;
465 domove();
466 } else {
467 --multi;
468 rhack(save_cm);
469 }
470 } else if (multi == 0) {
471 #ifdef MAIL
472 ckmailstatus();
473 #endif
474 rhack(NULL);
475 }
476 if (multi && multi % 7 == 0)
477 (void) fflush(stdout);
478 }
479 }
480
481 void
482 glo(int foo)
483 {
484 /* construct the string xlock.n */
485 size_t pos;
486
487 pos = 0;
488 while (lock[pos] && lock[pos] != '.')
489 pos++;
490 (void) snprintf(lock + pos, sizeof(lock) - pos, ".%d", foo);
491 }
492
493 /*
494 * plname is filled either by an option (-u Player or -uPlayer) or
495 * explicitly (-w implies wizard) or by askname.
496 * It may still contain a suffix denoting pl_character.
497 */
498 void
499 askname(void)
500 {
501 int c, ct;
502 printf("\nWho are you? ");
503 (void) fflush(stdout);
504 ct = 0;
505 while ((c = getchar()) != '\n') {
506 if (c == EOF)
507 error("End of input\n");
508 /* some people get confused when their erase char is not ^H */
509 if (c == '\010') {
510 if (ct)
511 ct--;
512 continue;
513 }
514 if (c != '-')
515 if (c < 'A' || (c > 'Z' && c < 'a') || c > 'z')
516 c = '_';
517 if (ct < (int)sizeof(plname) - 1)
518 plname[ct++] = c;
519 }
520 plname[ct] = 0;
521 if (ct == 0)
522 askname();
523 }
524
525 /* VARARGS1 */
526 void
527 impossible(const char *s, ...)
528 {
529 va_list ap;
530
531 va_start(ap, s);
532 vpline(s, ap);
533 va_end(ap);
534 pline("Program in disorder - perhaps you'd better Quit.");
535 }
536
537 #ifdef CHDIR
538 static void
539 chdirx(const char *dir, boolean wr)
540 {
541
542 #ifdef SECURE
543 if (dir /* User specified directory? */
544 #ifdef HACKDIR
545 && strcmp(dir, HACKDIR) /* and not the default? */
546 #endif
547 ) {
548 (void) setuid(getuid()); /* Ron Wessels */
549 (void) setgid(getgid());
550 }
551 #endif
552
553 #ifdef HACKDIR
554 if (dir == NULL)
555 dir = HACKDIR;
556 #endif
557
558 if (dir && chdir(dir) < 0) {
559 perror(dir);
560 error("Cannot chdir to %s.", dir);
561 }
562 /* warn the player if he cannot write the record file */
563 /* perhaps we should also test whether . is writable */
564 /* unfortunately the access systemcall is worthless */
565 if (wr) {
566 int fd;
567
568 if (dir == NULL)
569 dir = ".";
570 if ((fd = open(RECORD, O_RDWR)) < 0) {
571 printf("Warning: cannot write %s/%s", dir, RECORD);
572 getret();
573 } else
574 (void) close(fd);
575 }
576 }
577 #endif
578
579 void
580 stop_occupation(void)
581 {
582 if (occupation) {
583 pline("You stop %s.", occtxt);
584 occupation = 0;
585 }
586 }