1 /* $NetBSD: hack.main.c,v 1.13 2009/06/29 23:05:33 dholland Exp $ */
4 * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
12 * - Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
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.
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
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.
38 * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
39 * All rights reserved.
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
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.
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.
64 #include <sys/cdefs.h>
66 __RCSID("$NetBSD: hack.main.c,v 1.13 2009/06/29 23:05:33 dholland Exp $");
77 #define gamename "quest"
79 #define gamename "hack"
82 int (*afternmv
)(void);
83 int (*occupation
)(void);
84 const char *occtxt
; /* defined when occupation != NULL */
86 int hackpid
; /* current pid */
87 int locknum
; /* max num of players */
89 const char *catmore
; /* default pager */
91 char SAVEF
[PL_NSIZ
+ 11] = "save/"; /* save/99999player */
92 char *hname
; /* name of the game (argv[0] of call) */
94 static char obuf
[BUFSIZ
]; /* BUFSIZ is defined in stdio.h */
96 int main(int, char *[]);
97 static void chdirx(const char *, boolean
);
100 main(int argc
, char *argv
[])
107 /* Check for dirty tricks with closed fds 0, 1, 2 */
108 fd
= open("/dev/null", O_RDONLY
);
116 #ifdef CHDIR /* otherwise no chdir() */
118 * See if we must change directory to the playground.
119 * (Perhaps hack runs suid and playground is inaccessible
121 * The environment variable HACKDIR is overridden by a
122 * -d command line option (must be the first option given)
125 dir
= getenv("HACKDIR");
126 if (argc
> 1 && !strncmp(argv
[1], "-d", 2)) {
130 if (*dir
== '=' || *dir
== ':')
132 if (!*dir
&& argc
> 1) {
138 error("Flag -d must be followed by a directory name.");
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
150 * Note that we trust him here; it is possible to play under
151 * somebody else's name.
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);
166 * Now we know the directory containing 'record' and
167 * may do a prscore().
169 if (argc
> 1 && !strncmp(argv
[1], "-s", 2)) {
177 * It seems he really wants to play.
178 * Remember tty modes, to be restored on exit.
181 setbuf(stdout
, obuf
);
185 u
.uhp
= 1; /* prevent RIP on early quits */
186 u
.ux
= FAR
; /* prevent nscr() */
187 (void) signal(SIGHUP
, hangup
);
190 * Find the creation date of this game,
191 * so as to avoid restoring outdated savefiles.
196 * We cannot do chdir earlier, otherwise gethdate will fail.
205 while (argc
> 1 && argv
[1][0] == '-') {
208 switch (argv
[0][1]) {
211 /* if(!strcmp(getlogin(), WIZARD)) */
214 * else printf("Sorry.\n");
225 (void) strncpy(plname
, argv
[0] + 2, sizeof(plname
) - 1);
229 (void) strncpy(plname
, argv
[0], sizeof(plname
) - 1);
231 printf("Player name expected after -u\n");
234 /* allow -T for Tourist, etc. */
235 (void) strncpy(pl_character
, argv
[0] + 1,
236 sizeof(pl_character
) - 1);
238 /* printf("Unknown option: %s\n", *argv); */
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
;
249 if (((catmore
= getenv("HACKPAGER")) == NULL
&&
250 (catmore
= getenv("PAGER")) == NULL
) ||
259 (void) strcpy(plname
, "wizard");
262 if (!*plname
|| !strncmp(plname
, "player", 4)
263 || !strncmp(plname
, "games", 4))
265 plnamesuffix(); /* strip suffix from name; calls askname() */
266 /* again if suffix was whole name */
267 /* accepts any suffix */
272 * check for multiple games under the same name
273 * (if !locknum) or check max nr of players (otherwise)
275 (void) signal(SIGQUIT
, SIG_IGN
);
276 (void) signal(SIGINT
, SIG_IGN
);
278 (void) strcpy(lock
, plname
);
279 getlock(); /* sets lock if locknum != 0 */
283 (void) strcpy(lock
, plname
);
284 if ((sfoo
= getenv("MAGIC")) != NULL
)
288 (void) srandom(*sfoo
++);
292 if ((sfoo
= getenv("GENOCIDED")) != NULL
) {
294 const struct permonst
*pm
= mons
;
295 char *gp
= genocided
;
297 while (pm
< mons
+ CMNUM
+ 2) {
298 if (!strchr(sfoo
, pm
->mlet
))
304 (void) strlcpy(genocided
, sfoo
,
306 (void) strcpy(fut_geno
, genocided
);
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
);
320 pline("Hello %s, welcome to %s!", plname
, gamename
);
324 fobj
= fcobj
= invent
= 0;
325 fmon
= fallen_down
= 0;
332 (void) signal(SIGINT
, done1
);
342 if ((mtmp
= m_at(u
.ux
, u
.uy
)) != NULL
)
343 mnexto(mtmp
); /* riv05!a3 */
347 if (flags
.nonews
|| !readnews())
348 /* after reading news we did docrt() already */
352 /* give welcome message before pickup messages */
353 pline("Hello %s, welcome to %s!", plname
, gamename
);
356 read_engr_at(u
.ux
, u
.uy
);
360 flags
.moonphase
= phase_of_the_moon();
361 if (flags
.moonphase
== FULL_MOON
) {
362 pline("You are lucky! Full moon tonight.");
364 } else if (flags
.moonphase
== NEW_MOON
) {
365 pline("Be careful! New moon tonight.");
370 if (flags
.move
) { /* actual time passed */
374 if (moves
% 2 == 0 ||
375 (!(Fast
& ~INTRINSIC
) && (!Fast
|| rn2(3)))) {
378 (void) makemon((struct permonst
*) 0, 0, 0);
390 if (u
.uhp
* 10 < u
.uhpmax
&& moves
- wailmsg
> 50) {
393 pline("You hear the wailing of the Banshee...");
395 pline("You hear the howling of the CwnAnnwn...");
397 if (u
.uhp
< u
.uhpmax
) {
399 if (Regeneration
|| !(moves
% 3)) {
401 u
.uhp
+= rnd((int) u
.ulevel
- 9);
402 if (u
.uhp
> u
.uhpmax
)
405 } else if (Regeneration
||
406 (!(moves
% (22 - u
.ulevel
* 2)))) {
411 if (Teleportation
&& !rn2(85))
413 if (Searching
&& multi
>= 0)
421 pline(nomovemsg
? nomovemsg
:
422 "You can move again.");
431 if (!flags
.mv
|| Blind
)
438 if (flags
.botl
|| flags
.botlx
)
443 if (multi
>= 0 && occupation
) {
444 if (monster_nearby())
446 else if ((*occupation
) () == 0)
456 if (!multi
) { /* lookaround may clear multi */
461 if (multi
< COLNO
&& !--multi
)
462 flags
.mv
= flags
.run
= 0;
468 } else if (multi
== 0) {
474 if (multi
&& multi
% 7 == 0)
475 (void) fflush(stdout
);
482 /* construct the string xlock.n */
486 while (lock
[pos
] && lock
[pos
] != '.')
488 (void) snprintf(lock
+ pos
, sizeof(lock
) - pos
, ".%d", foo
);
492 * plname is filled either by an option (-u Player or -uPlayer) or
493 * explicitly (-w implies wizard) or by askname.
494 * It may still contain a suffix denoting pl_character.
500 printf("\nWho are you? ");
501 (void) fflush(stdout
);
503 while ((c
= getchar()) != '\n') {
505 error("End of input\n");
506 /* some people get confused when their erase char is not ^H */
513 if (c
< 'A' || (c
> 'Z' && c
< 'a') || c
> 'z')
515 if (ct
< (int)sizeof(plname
) - 1)
525 impossible(const char *s
, ...)
532 pline("Program in disorder - perhaps you'd better Quit.");
537 chdirx(const char *dir
, boolean wr
)
541 if (dir
/* User specified directory? */
543 && strcmp(dir
, HACKDIR
) /* and not the default? */
546 (void) setuid(getuid()); /* Ron Wessels */
547 (void) setgid(getgid());
556 if (dir
&& chdir(dir
) < 0) {
558 error("Cannot chdir to %s.", dir
);
560 /* warn the player if he cannot write the record file */
561 /* perhaps we should also test whether . is writable */
562 /* unfortunately the access systemcall is worthless */
568 if ((fd
= open(RECORD
, O_RDWR
)) < 0) {
569 printf("Warning: cannot write %s/%s", dir
, RECORD
);
578 stop_occupation(void)
581 pline("You stop %s.", occtxt
);