/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.main.c version 1.0.1 - some cosmetic changes */

#include <stdio.h>
#ifndef AMIGA
#include <signal.h>
#endif
/* #include <errno.h> */
#include "hack.h"

extern char *getlogin();
extern char plname[PL_NSIZ], pl_character[PL_CSIZ];
extern char *getenv();

int (*afternmv)();

int done1();
int hangup();

char safelock[] = "safelock";
xchar locknum;            /* max num of players */
char SAVEF[PL_NSIZ + 22] = "Saved Games/";
char perm[] = "perm";
char *hname;      /* name of the game (argv[0] of call) */
char obuf[BUFSIZ];   /* BUFSIZ is defined in stdio.h */

extern char *nomovemsg;
extern long wailmsg;

main(argc,argv)
int argc;
char *argv[];
{
   int fd;
#ifdef NEWS
	int nonews = 0;
#endif NEWS
   char *dir;

   initterm();
#ifdef AMIGA
   if (argc == 0)
	{
	geticon();
	hname = HACKNAME;
	argc = 1;
	}
   else
#endif
   hname = argv[0];

   /*
    * 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.
    */
   if ( (dir = getenv("HACKDIR")) == NULL)
	dir = HACKDIR;

   if(argc > 1 && !strncmp(argv[1], "-d", 2)) {
      argc--;
      argv++;
      dir = argv[0]+2;
      if(*dir == '=' || *dir == ':') dir++;
      if(!*dir && argc > 1) {
         argc--;
         argv++;
         dir = argv[0];
      }
      if(!*dir)
		    error("Flag -d must be followed by a directory name.");
   }

   /*
    * Now we know the directory containing 'record' and
    * may do a prscore().
    */
   if(argc > 1 && !strncmp(argv[1], "-s", 2)) {
      if(dir) chdirx(dir);
      prscore(argc, argv);
      hackexit(0);
   }

   /*
    * It seems he really wants to play. 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.
    */
   if(dir) chdirx(dir);

   /*
    * Who am i? Perhaps we should use $USER instead?
    */
#ifdef AMIGA
   if (!*plname)
#endif
	(void) strncpy(plname, getlogin(), sizeof(plname)-1);

   /*
    * Process options.
    */
	initoptions();
   while(argc > 1 && argv[1][0] == '-'){
      argv++;
      argc--;
      switch(argv[0][1]){
#ifdef WIZARD
      case 'w':
         if(!strcmp(getlogin(), WIZARD))
            wizard = TRUE;
         else myprintf("Sorry.\n");
         break;
#endif WIZARD
#ifdef NEWS
		case 'n':
			flags.nonews = TRUE;
			break;
#endif NEWS
      case 'u':
         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);
         } else
            myprintf("Player name expected after -u\n");
         break;
      default:
         myprintf("Unknown option: %s\n", *argv);
      }
   }

   if(argc > 1)
      locknum = atoi(argv[1]);
#ifdef WIZARD
   if(wizard) (void) strcpy(plname, "wizard"); else
#endif WIZARD
   if(!*plname || !strncmp(plname, "player", 4)) askname();
#ifdef AMIGA
   if (!pl_character[0])
#endif
   plnamesuffix();      /* strip suffix from name */

   setbuf(stdout,obuf);
    (void) srand(getpid());
   startup();
   cls();
#ifndef AMIGA
   (void) signal(SIGHUP, hangup);
#endif
#ifdef WIZARD
   if(!wizard) {
#endif WIZARD
#ifndef AMIGA
      (void) signal(SIGQUIT,SIG_IGN);
      (void) signal(SIGINT,SIG_IGN);
#endif
      if(locknum)
         lockcheck();
      else
         (void) strcpy(lock,plname);
#ifdef WIZARD
   } else {
      register char *sfoo;
      (void) strcpy(lock,plname);
      if(sfoo = getenv("MAGIC"))
         while(*sfoo) {
            switch(*sfoo++) {
            case 'n': (void) srand(*sfoo++);
               break;
            }
         }
      if(sfoo = getenv("GENOCIDED")){
         if(*sfoo == '!'){
            extern struct permonst mons[PMONCOUNT];
            extern char genocided[], fut_geno[];
            register struct permonst *pm = mons;
            register char *gp = genocided;

            while(pm < mons+CMNUM+2){
               if(!index(sfoo, pm->mlet))
                  *gp++ = pm->mlet;
               pm++;
            }
            *gp = 0;
         } else
            (void) strcpy(genocided, sfoo);
         (void) strcpy(fut_geno, genocided);
      }
   }
#endif WIZARD
   u.uhp = 1;   /* prevent RIP on early quits */
   u.ux = FAR;   /* prevent nscr() */
   (void) strcat(SAVEF,plname);
   if((fd = open(SAVEF,0)) >= 0 &&
      (uptodate(fd) || unlink(SAVEF) == 666)) {
#ifndef AMIGA
      (void) signal(SIGINT,done1);
#endif
      myputs("Restoring old save file...");
      (void) myfflush(stdout);
      dorecover(fd);
      flags.move = 0;
   } else {
#ifdef NEWS
	if(!flags.nonews)
		if((fd = open(NEWS,0)) >= 0)
			outnews(fd);
#endif NEWS
      flags.ident = 1;
      init_objects(0);
      u_init();
#ifndef AMIGA
      (void) signal(SIGINT,done1);
#endif
      glo(1);
      mklev();
      u.ux = xupstair;
      u.uy = yupstair;
      (void) inshop();
      setsee();
      flags.botlx = 1;
      makedog();
      seemons();
      docrt();
      pickup();
      read_engr_at(u.ux,u.uy);   /* superfluous ? */
      flags.move = 1;
      flags.cbreak = ON;
      flags.echo = OFF;
   }
   setftty();
#ifdef TRACK
   initrack();
#endif TRACK
   for(;;) {
      if(flags.move) {
#ifdef TRACK
         settrack();
#endif TRACK
         if(moves%2 == 0 ||
           (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) {
            extern struct monst *makemon();
            movemon();
            if(!rn2(70))
                (void) makemon((struct permonst *)0, 0, 0);
         }
         if(Glib) glibr();
         timeout();
			++moves;
			if(flags.time) flags.botl = 1;
			if(u.uhp < 1) {
				pline("You die...");
				done("died");
				}
         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...");
         }
         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;
               }
            } else if(Regeneration ||
               (!(moves%(22-u.ulevel*2)))) {
               flags.botl = 1;
               u.uhp++;
            }
         }
         if(Teleportation && !rn2(85)) tele();
         if(Searching && multi >= 0) (void) dosearch();
         gethungry();
         invault();
      }
      if(multi < 0) {
         if(!++multi){
            pline(nomovemsg ? nomovemsg :
               "You can move again.");
            nomovemsg = 0;
            if(afternmv) (*afternmv)();
            afternmv = 0;
         }
      }
      flags.move = 1;
      find_ac();
#ifndef QUEST
      if(!flags.mv || Blind)
#endif QUEST
      {
         seeobjs();
         seemons();
         nscr();
      }
      if(flags.botl || flags.botlx) bot();
      if(multi > 0) {
#ifdef QUEST
         if(flags.run >= 4) finddir();
#endif QUEST
         lookaround();
         if(!multi) {   /* lookaround may clear multi */
            flags.move = 0;
            continue;
         }
         if(flags.mv) {
            if(multi<COLNO && !--multi)
               flags.mv = flags.run = 0;
            domove();
         } else {
            --multi;
            rhack(save_cm);
         }
		} else if(multi == 0)
			rhack((char *) 0);
		if(multi && multi%7 == 0)
			(void) fflush(stdout);
   }
}

lockcheck()
{
/*   extern int errno;                         */
/*   register int i, fd;                       */
/*                                             */
/* we ignore QUIT and INT at this point        */
/*    if (link(perm,safelock) == -1)           */
/*        error("Cannot link safelock. (Try again or rm safelock.)");*/
/*                                             */
/*                                             */
/*    for(i = 0; i < locknum; i++) {           */
/*       lock[0]= 'a' + i;                     */
/*       if((fd = open(lock,0)) == -1) {       */
/*          if(errno == ENOENT) goto gotlock;  */  /* no such file */
/*          (void) unlink(safelock);           */
/*          error("Cannot open %s", lock);	*/
/*       }					*/
/*       (void) close(fd);			*/
/*    }						*/
/*     (void) unlink(safelock);			*/
/*   error("Too many hacks running now.");	*/
/*	}					*/
/* gotlock:					*/
/*    fd = creat(lock,FMASK);                  */
/*	if(unlink(safelock) == -1) {		*/
/*		error("Cannot unlink safelock.");*/
/*    if(fd == -1) {                           */
/*       error("cannot creat lock file.");     */
/*    } else {                                 */
/*       int pid;                              */
/*                                             */
/*       pid = getpid();                       */ 
/*		if(write(fd, (char *) &pid, sizeof(pid)) != sizeof(pid)){ */
/*          error("cannot write lock");        */
/*       }                                     */
/*	if(close(fd) == -1) {			*/
/*          error("cannot close lock");        */
/*       }                                     */
/*    }                                        */
}

/*VARARGS1*/
error(s,a1,a2,a3,a4) char *s,*a1,*a2,*a3,*a4;
   {
   myprintf("Error: ");
   myprintf(s,a1,a2,a3,a4);
   (void) myputchar('\n');
   hackexit(1);
   }

glo(foo)
register int foo;
{
   /* construct the string  xlock.n  */
   register char *tf;

   tf = lock;
   while(*tf && *tf!='.') tf++;
   (void) sprintf(tf, ".%d", foo);
}

/*
 * 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.
 */
askname(){
register int c,ct;
   myprintf("\nWho are you? ");
   ct = 0;
   (void) myfflush();
   while((c = inchar()) != '\n')
      {
      if (c != '-')
         if (c == 8) { /* backspace */
            if (ct) {
		ct--;
		backsp();
		myputchar(' ');
		backsp();
		myfflush();
		}
	    continue;
            }
         else
            if (c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_';
               if (ct < sizeof(plname)-1)
                  {
                  plname[ct++] = c;
                  myprintf("%c", c);
                  }
	(void) myfflush();
      }
   plname[ct] = 0;
   if(ct == 0) askname();
#ifdef QUEST
   else myprintf("Hello %s, welcome to quest!\n", plname);
#else
   else myprintf("Hello %s, welcome to hack!\n", plname);
#endif QUEST
}

impossible(){
   pline("Program in disorder - perhaps you'd better Quit");
}

#ifdef NEWS
int stopnews;

stopnws(){
#ifndef AMIGA
   (void) signal(SIGINT, SIG_IGN);
#endif
   stopnews++;
}

outnews(fd) int fd; {
int (*prevsig)();
char ch;
#ifndef AMIGA
   prevsig = signal(SIGINT, stopnws);
#endif
   while(!stopnews && read(fd,&ch,1) == 1)
      (void) myputchar(ch);
   (void) myputchar('\n');
   (void) myfflush(stdout);
   (void) close(fd);
#ifndef AMIGA
   (void) signal(SIGINT, prevsig);
#endif
   /* See whether we will ask TSKCFW: he might have told us already */
   if(!stopnews && pl_character[0])
      getret();
}
#endif NEWS

chdirx(dir) char *dir; {
   if(chdir(dir) < 0) {
      perror(dir);
      error("Cannot chdir to %s.", dir);
   }
}
