NetBSD/games/hack/hack.main.c

585 lines
14 KiB
C
Raw Normal View History

2009-08-12 11:28:40 +04:00
/* $NetBSD: hack.main.c,v 1.14 2009/08/12 07:28:40 dholland Exp $ */
1997-10-19 20:56:41 +04:00
1993-08-02 21:16:36 +04:00
/*
* Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
* Amsterdam
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Stichting Centrum voor Wiskunde en
* Informatica, nor the names of its contributors may be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1993-08-02 21:16:36 +04:00
*/
1997-10-19 20:56:41 +04:00
#include <sys/cdefs.h>
1993-08-02 21:16:36 +04:00
#ifndef lint
2009-08-12 11:28:40 +04:00
__RCSID("$NetBSD: hack.main.c,v 1.14 2009/08/12 07:28:40 dholland Exp $");
1997-10-19 20:56:41 +04:00
#endif /* not lint */
1993-03-21 12:45:37 +03:00
#include <signal.h>
1997-10-19 20:56:41 +04:00
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
1993-03-21 12:45:37 +03:00
#include "hack.h"
1997-10-19 20:56:41 +04:00
#include "extern.h"
1993-03-21 12:45:37 +03:00
#ifdef QUEST
#define gamename "quest"
#else
#define gamename "hack"
#endif
2004-01-27 23:30:28 +03:00
int (*afternmv)(void);
int (*occupation)(void);
const char *occtxt; /* defined when occupation != NULL */
1993-03-21 12:45:37 +03:00
1997-10-19 20:56:41 +04:00
int hackpid; /* current pid */
int locknum; /* max num of players */
1993-03-21 12:45:37 +03:00
#ifdef DEF_PAGER
const char *catmore; /* default pager */
1993-03-21 12:45:37 +03:00
#endif
1997-10-19 20:56:41 +04:00
char SAVEF[PL_NSIZ + 11] = "save/"; /* save/99999player */
char *hname; /* name of the game (argv[0] of call) */
2009-08-12 11:28:40 +04:00
static char obuf[BUFSIZ]; /* BUFSIZ is defined in stdio.h */
1993-03-21 12:45:37 +03:00
2004-01-27 23:30:28 +03:00
int main(int, char *[]);
static void chdirx(const char *, boolean);
1993-03-21 12:45:37 +03:00
1997-10-19 20:56:41 +04:00
int
main(int argc, char *argv[])
1993-03-21 12:45:37 +03:00
{
1997-10-19 20:56:41 +04:00
int fd;
1993-03-21 12:45:37 +03:00
#ifdef CHDIR
1997-10-19 20:56:41 +04:00
char *dir;
1993-03-21 12:45:37 +03:00
#endif
/* Check for dirty tricks with closed fds 0, 1, 2 */
fd = open("/dev/null", O_RDONLY);
if (fd < 3)
exit(1);
close(fd);
1993-03-21 12:45:37 +03:00
hname = argv[0];
hackpid = getpid();
#ifdef CHDIR /* otherwise no chdir() */
/*
* See if we must change directory to the playground.
* (Perhaps hack runs suid and playground is inaccessible
* for the player.)
* The environment variable HACKDIR is overridden by a
* -d command line option (must be the first option given)
*/
dir = getenv("HACKDIR");
1997-10-19 20:56:41 +04:00
if (argc > 1 && !strncmp(argv[1], "-d", 2)) {
1993-03-21 12:45:37 +03:00
argc--;
argv++;
1997-10-19 20:56:41 +04:00
dir = argv[0] + 2;
if (*dir == '=' || *dir == ':')
dir++;
if (!*dir && argc > 1) {
1993-03-21 12:45:37 +03:00
argc--;
argv++;
dir = argv[0];
}
1997-10-19 20:56:41 +04:00
if (!*dir)
error("Flag -d must be followed by a directory name.");
1993-03-21 12:45:37 +03:00
}
#endif
/*
* Who am i? Algorithm: 1. Use name as specified in HACKOPTIONS
* 2. Use $USER or $LOGNAME (if 1. fails)
* 3. Use getlogin() (if 2. fails)
* The resulting name is overridden by command line options.
* If everything fails, or if the resulting name is some generic
* account like "games", "play", "player", "hack" then eventually
* we'll ask him.
* Note that we trust him here; it is possible to play under
* somebody else's name.
*/
1997-10-19 20:56:41 +04:00
{
char *s;
initoptions();
if (!*plname && (s = getenv("USER")))
(void) strncpy(plname, s, sizeof(plname) - 1);
if (!*plname && (s = getenv("LOGNAME")))
(void) strncpy(plname, s, sizeof(plname) - 1);
if (!*plname && (s = getlogin()))
(void) strncpy(plname, s, sizeof(plname) - 1);
1993-03-21 12:45:37 +03:00
}
/*
* Now we know the directory containing 'record' and
* may do a prscore().
*/
1997-10-19 20:56:41 +04:00
if (argc > 1 && !strncmp(argv[1], "-s", 2)) {
1993-03-21 12:45:37 +03:00
#ifdef CHDIR
1997-10-19 20:56:41 +04:00
chdirx(dir, 0);
1993-03-21 12:45:37 +03:00
#endif
prscore(argc, argv);
exit(0);
}
/*
* It seems he really wants to play.
* Remember tty modes, to be restored on exit.
*/
gettty();
1997-10-19 20:56:41 +04:00
setbuf(stdout, obuf);
1993-03-21 12:45:37 +03:00
setrandom();
startup();
cls();
1997-10-19 20:56:41 +04:00
u.uhp = 1; /* prevent RIP on early quits */
u.ux = FAR; /* prevent nscr() */
1993-03-21 12:45:37 +03:00
(void) signal(SIGHUP, hangup);
/*
* Find the creation date of this game,
* so as to avoid restoring outdated savefiles.
*/
gethdate(hname);
/*
* We cannot do chdir earlier, otherwise gethdate will fail.
*/
#ifdef CHDIR
1997-10-19 20:56:41 +04:00
chdirx(dir, 1);
1993-03-21 12:45:37 +03:00
#endif
/*
* Process options.
*/
1997-10-19 20:56:41 +04:00
while (argc > 1 && argv[1][0] == '-') {
1993-03-21 12:45:37 +03:00
argv++;
argc--;
1997-10-19 20:56:41 +04:00
switch (argv[0][1]) {
1993-03-21 12:45:37 +03:00
#ifdef WIZARD
case 'D':
1997-10-19 20:56:41 +04:00
/* if(!strcmp(getlogin(), WIZARD)) */
wizard = TRUE;
/*
* else printf("Sorry.\n");
*/
1993-03-21 12:45:37 +03:00
break;
#endif
#ifdef NEWS
case 'n':
flags.nonews = TRUE;
break;
#endif
case 'u':
1997-10-19 20:56:41 +04:00
if (argv[0][2])
(void) strncpy(plname, argv[0] + 2, sizeof(plname) - 1);
else if (argc > 1) {
argc--;
argv++;
(void) strncpy(plname, argv[0], sizeof(plname) - 1);
1993-03-21 12:45:37 +03:00
} else
printf("Player name expected after -u\n");
break;
default:
/* allow -T for Tourist, etc. */
1997-10-19 20:56:41 +04:00
(void) strncpy(pl_character, argv[0] + 1,
sizeof(pl_character) - 1);
1993-03-21 12:45:37 +03:00
/* printf("Unknown option: %s\n", *argv); */
}
}
1997-10-19 20:56:41 +04:00
if (argc > 1)
1993-03-21 12:45:37 +03:00
locknum = atoi(argv[1]);
#ifdef MAX_NR_OF_PLAYERS
1997-10-19 20:56:41 +04:00
if (!locknum || locknum > MAX_NR_OF_PLAYERS)
1993-03-21 12:45:37 +03:00
locknum = MAX_NR_OF_PLAYERS;
#endif
#ifdef DEF_PAGER
2000-03-02 21:19:06 +03:00
if (((catmore = getenv("HACKPAGER")) == NULL &&
(catmore = getenv("PAGER")) == NULL) ||
catmore[0] == '\0')
1993-03-21 12:45:37 +03:00
catmore = DEF_PAGER;
#endif
#ifdef MAIL
getmailstatus();
#endif
#ifdef WIZARD
1997-10-19 20:56:41 +04:00
if (wizard)
(void) strcpy(plname, "wizard");
else
1993-03-21 12:45:37 +03:00
#endif
1997-10-19 20:56:41 +04:00
if (!*plname || !strncmp(plname, "player", 4)
1993-03-21 12:45:37 +03:00
|| !strncmp(plname, "games", 4))
askname();
plnamesuffix(); /* strip suffix from name; calls askname() */
1997-10-19 20:56:41 +04:00
/* again if suffix was whole name */
/* accepts any suffix */
1993-03-21 12:45:37 +03:00
#ifdef WIZARD
1997-10-19 20:56:41 +04:00
if (!wizard) {
1993-03-21 12:45:37 +03:00
#endif
/*
* check for multiple games under the same name
* (if !locknum) or check max nr of players (otherwise)
*/
1997-10-19 20:56:41 +04:00
(void) signal(SIGQUIT, SIG_IGN);
(void) signal(SIGINT, SIG_IGN);
if (!locknum)
(void) strcpy(lock, plname);
1993-03-21 12:45:37 +03:00
getlock(); /* sets lock if locknum != 0 */
#ifdef WIZARD
} else {
1997-10-19 20:56:41 +04:00
char *sfoo;
(void) strcpy(lock, plname);
if ((sfoo = getenv("MAGIC")) != NULL)
while (*sfoo) {
switch (*sfoo++) {
case 'n':
(void) srandom(*sfoo++);
1993-03-21 12:45:37 +03:00
break;
}
}
1997-10-19 20:56:41 +04:00
if ((sfoo = getenv("GENOCIDED")) != NULL) {
if (*sfoo == '!') {
const struct permonst *pm = mons;
1997-10-19 20:56:41 +04:00
char *gp = genocided;
1993-03-21 12:45:37 +03:00
1997-10-19 20:56:41 +04:00
while (pm < mons + CMNUM + 2) {
if (!strchr(sfoo, pm->mlet))
1993-03-21 12:45:37 +03:00
*gp++ = pm->mlet;
pm++;
}
*gp = 0;
} else
(void) strlcpy(genocided, sfoo,
sizeof(genocided));
1993-03-21 12:45:37 +03:00
(void) strcpy(fut_geno, genocided);
}
}
#endif
setftty();
(void) snprintf(SAVEF, sizeof(SAVEF), "save/%d%s", getuid(), plname);
1997-10-19 20:56:41 +04:00
regularize(SAVEF + 5); /* avoid . or / in name */
if ((fd = open(SAVEF, O_RDONLY)) >= 0 &&
1997-10-19 20:56:41 +04:00
(uptodate(fd) || unlink(SAVEF) == 666)) {
(void) signal(SIGINT, done1);
1993-03-21 12:45:37 +03:00
pline("Restoring old save file...");
(void) fflush(stdout);
1997-10-19 20:56:41 +04:00
if (!dorecover(fd))
1993-03-21 12:45:37 +03:00
goto not_recovered;
pline("Hello %s, welcome to %s!", plname, gamename);
flags.move = 0;
} else {
not_recovered:
fobj = fcobj = invent = 0;
fmon = fallen_down = 0;
ftrap = 0;
fgold = 0;
flags.ident = 1;
init_objects();
u_init();
1997-10-19 20:56:41 +04:00
(void) signal(SIGINT, done1);
1993-03-21 12:45:37 +03:00
mklev();
u.ux = xupstair;
u.uy = yupstair;
(void) inshop();
setsee();
flags.botlx = 1;
makedog();
1997-10-19 20:56:41 +04:00
{
struct monst *mtmp;
if ((mtmp = m_at(u.ux, u.uy)) != NULL)
mnexto(mtmp); /* riv05!a3 */
1993-03-21 12:45:37 +03:00
}
seemons();
#ifdef NEWS
1997-10-19 20:56:41 +04:00
if (flags.nonews || !readnews())
1993-03-21 12:45:37 +03:00
/* after reading news we did docrt() already */
#endif
docrt();
/* give welcome message before pickup messages */
pline("Hello %s, welcome to %s!", plname, gamename);
pickup(1);
1997-10-19 20:56:41 +04:00
read_engr_at(u.ux, u.uy);
1993-03-21 12:45:37 +03:00
flags.move = 1;
}
flags.moonphase = phase_of_the_moon();
1997-10-19 20:56:41 +04:00
if (flags.moonphase == FULL_MOON) {
1993-03-21 12:45:37 +03:00
pline("You are lucky! Full moon tonight.");
u.uluck++;
1997-10-19 20:56:41 +04:00
} else if (flags.moonphase == NEW_MOON) {
1993-03-21 12:45:37 +03:00
pline("Be careful! New moon tonight.");
}
initrack();
1997-10-19 20:56:41 +04:00
for (;;) {
if (flags.move) { /* actual time passed */
1993-03-21 12:45:37 +03:00
settrack();
1997-10-19 20:56:41 +04:00
if (moves % 2 == 0 ||
(!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) {
1993-03-21 12:45:37 +03:00
movemon();
1997-10-19 20:56:41 +04:00
if (!rn2(70))
(void) makemon((struct permonst *) 0, 0, 0);
1993-03-21 12:45:37 +03:00
}
1997-10-19 20:56:41 +04:00
if (Glib)
glibr();
1993-03-21 12:45:37 +03:00
timeout();
++moves;
1997-10-19 20:56:41 +04:00
if (flags.time)
flags.botl = 1;
if (u.uhp < 1) {
1993-03-21 12:45:37 +03:00
pline("You die...");
done("died");
}
1997-10-19 20:56:41 +04:00
if (u.uhp * 10 < u.uhpmax && moves - wailmsg > 50) {
wailmsg = moves;
if (u.uhp == 1)
pline("You hear the wailing of the Banshee...");
else
pline("You hear the howling of the CwnAnnwn...");
1993-03-21 12:45:37 +03:00
}
1997-10-19 20:56:41 +04:00
if (u.uhp < u.uhpmax) {
if (u.ulevel > 9) {
if (Regeneration || !(moves % 3)) {
flags.botl = 1;
u.uhp += rnd((int) u.ulevel - 9);
if (u.uhp > u.uhpmax)
u.uhp = u.uhpmax;
1993-03-21 12:45:37 +03:00
}
1997-10-19 20:56:41 +04:00
} else if (Regeneration ||
(!(moves % (22 - u.ulevel * 2)))) {
1993-03-21 12:45:37 +03:00
flags.botl = 1;
u.uhp++;
}
}
1997-10-19 20:56:41 +04:00
if (Teleportation && !rn2(85))
tele();
if (Searching && multi >= 0)
(void) dosearch();
1993-03-21 12:45:37 +03:00
gethungry();
invault();
amulet();
}
1997-10-19 20:56:41 +04:00
if (multi < 0) {
if (!++multi) {
1993-03-21 12:45:37 +03:00
pline(nomovemsg ? nomovemsg :
1997-10-19 20:56:41 +04:00
"You can move again.");
1993-03-21 12:45:37 +03:00
nomovemsg = 0;
1997-10-19 20:56:41 +04:00
if (afternmv)
(*afternmv) ();
1993-03-21 12:45:37 +03:00
afternmv = 0;
}
}
find_ac();
#ifndef QUEST
1997-10-19 20:56:41 +04:00
if (!flags.mv || Blind)
1993-03-21 12:45:37 +03:00
#endif
{
seeobjs();
seemons();
nscr();
}
1997-10-19 20:56:41 +04:00
if (flags.botl || flags.botlx)
bot();
1993-03-21 12:45:37 +03:00
flags.move = 1;
1997-10-19 20:56:41 +04:00
if (multi >= 0 && occupation) {
if (monster_nearby())
1993-03-21 12:45:37 +03:00
stop_occupation();
1997-10-19 20:56:41 +04:00
else if ((*occupation) () == 0)
1993-03-21 12:45:37 +03:00
occupation = 0;
continue;
}
1997-10-19 20:56:41 +04:00
if (multi > 0) {
1993-03-21 12:45:37 +03:00
#ifdef QUEST
1997-10-19 20:56:41 +04:00
if (flags.run >= 4)
finddir();
1993-03-21 12:45:37 +03:00
#endif
lookaround();
1997-10-19 20:56:41 +04:00
if (!multi) { /* lookaround may clear multi */
1993-03-21 12:45:37 +03:00
flags.move = 0;
continue;
}
1997-10-19 20:56:41 +04:00
if (flags.mv) {
if (multi < COLNO && !--multi)
1993-03-21 12:45:37 +03:00
flags.mv = flags.run = 0;
domove();
} else {
--multi;
rhack(save_cm);
}
1997-10-19 20:56:41 +04:00
} else if (multi == 0) {
1993-03-21 12:45:37 +03:00
#ifdef MAIL
ckmailstatus();
#endif
rhack((char *) 0);
}
1997-10-19 20:56:41 +04:00
if (multi && multi % 7 == 0)
1993-03-21 12:45:37 +03:00
(void) fflush(stdout);
}
}
1997-10-19 20:56:41 +04:00
void
glo(int foo)
1993-03-21 12:45:37 +03:00
{
/* construct the string xlock.n */
size_t pos;
1993-03-21 12:45:37 +03:00
pos = 0;
while (lock[pos] && lock[pos] != '.')
pos++;
(void) snprintf(lock + pos, sizeof(lock) - pos, ".%d", foo);
1993-03-21 12:45:37 +03:00
}
/*
* plname is filled either by an option (-u Player or -uPlayer) or
* explicitly (-w implies wizard) or by askname.
* It may still contain a suffix denoting pl_character.
*/
1997-10-19 20:56:41 +04:00
void
askname(void)
1997-10-19 20:56:41 +04:00
{
int c, ct;
1993-03-21 12:45:37 +03:00
printf("\nWho are you? ");
(void) fflush(stdout);
ct = 0;
1997-10-19 20:56:41 +04:00
while ((c = getchar()) != '\n') {
if (c == EOF)
error("End of input\n");
1993-03-21 12:45:37 +03:00
/* some people get confused when their erase char is not ^H */
1997-10-19 20:56:41 +04:00
if (c == '\010') {
if (ct)
ct--;
1993-03-21 12:45:37 +03:00
continue;
}
1997-10-19 20:56:41 +04:00
if (c != '-')
if (c < 'A' || (c > 'Z' && c < 'a') || c > 'z')
c = '_';
2008-01-28 09:55:41 +03:00
if (ct < (int)sizeof(plname) - 1)
1997-10-19 20:56:41 +04:00
plname[ct++] = c;
1993-03-21 12:45:37 +03:00
}
plname[ct] = 0;
1997-10-19 20:56:41 +04:00
if (ct == 0)
askname();
1993-03-21 12:45:37 +03:00
}
1997-10-19 20:56:41 +04:00
/* VARARGS1 */
void
impossible(const char *s, ...)
1993-03-21 12:45:37 +03:00
{
1997-10-19 20:56:41 +04:00
va_list ap;
va_start(ap, s);
vpline(s, ap);
va_end(ap);
1993-03-21 12:45:37 +03:00
pline("Program in disorder - perhaps you'd better Quit.");
}
#ifdef CHDIR
static void
chdirx(const char *dir, boolean wr)
1993-03-21 12:45:37 +03:00
{
#ifdef SECURE
1997-10-19 20:56:41 +04:00
if (dir /* User specified directory? */
1993-03-21 12:45:37 +03:00
#ifdef HACKDIR
1997-10-19 20:56:41 +04:00
&& strcmp(dir, HACKDIR) /* and not the default? */
1993-03-21 12:45:37 +03:00
#endif
) {
1997-10-19 20:56:41 +04:00
(void) setuid(getuid()); /* Ron Wessels */
1993-03-21 12:45:37 +03:00
(void) setgid(getgid());
}
#endif
#ifdef HACKDIR
1997-10-19 20:56:41 +04:00
if (dir == NULL)
1993-03-21 12:45:37 +03:00
dir = HACKDIR;
#endif
1997-10-19 20:56:41 +04:00
if (dir && chdir(dir) < 0) {
1993-03-21 12:45:37 +03:00
perror(dir);
error("Cannot chdir to %s.", dir);
}
/* warn the player if he cannot write the record file */
/* perhaps we should also test whether . is writable */
/* unfortunately the access systemcall is worthless */
1997-10-19 20:56:41 +04:00
if (wr) {
int fd;
if (dir == NULL)
dir = ".";
if ((fd = open(RECORD, O_RDWR)) < 0) {
1997-10-19 20:56:41 +04:00
printf("Warning: cannot write %s/%s", dir, RECORD);
getret();
} else
(void) close(fd);
1993-03-21 12:45:37 +03:00
}
}
#endif
1997-10-19 20:56:41 +04:00
void
stop_occupation(void)
1993-03-21 12:45:37 +03:00
{
1997-10-19 20:56:41 +04:00
if (occupation) {
1993-03-21 12:45:37 +03:00
pline("You stop %s.", occtxt);
occupation = 0;
}
}