/* * main.c - setup code * * Advanced Rogue * Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T * All rights reserved. * * Based on "Rogue: Exploring the Dungeons of Doom" * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman * All rights reserved. * * See the file LICENSE.TXT for full copyright and licensing information. */ #include "curses.h" #include #include #include #include #ifdef BSD #include #else #include #endif #include "mach_dep.h" #include "network.h" #include "rogue.h" #ifdef PC7300 #include "sys/window.h" #include extern struct uwdata wdata, oldwin; extern char oldtext[WTXTNUM][WTXTLEN]; #endif void open_records(void); bool too_much(void); bool author(void); void chmsg(char *fmt, int arg); #ifdef MAXPROCESSES int loadav(void); #endif #ifdef MAXUSERS int ucount(void); #endif bool holiday(void); int main(int argc, char *argv[], char *envp[]) { register char *env; #ifdef PC7300 int hardwindow; /* Do we have a hardware window? */ #endif md_init(); /* * get home and options from environment */ strncpy(home, md_gethomedir(), LINELEN); /* Get default save file */ strcpy(file_name, home); strcat(file_name, "arogue77.sav"); /* Get default score file */ #ifdef SCOREFILE strncpy(score_file, SCOREFILE, LINELEN); score_file[LINELEN-1] = '\0'; #else strcpy(score_file, md_getroguedir()); if (*score_file) strcat(score_file,"/"); strcat(score_file,"arogue77.scr"); #endif #ifdef SAVEDIR /* Check for common save location */ if (argc >= 3 && strcmp(argv[1], "-n") == 0) { strncpy(whoami, argv[2], 79); whoami[79] = '\0'; use_savedir = TRUE; if (LINELEN <= snprintf(file_name, LINELEN, "%s/%d-%s.ar7sav", SAVEDIR, md_getuid(), whoami)) { strcpy(file_name, "xrogue.sav"); use_savedir = FALSE; } } #endif if ((env = getenv("ROGUEOPTS")) != NULL) parse_opts(env); if (whoami[0] == '\0') strucpy(whoami, md_getusername(), strlen(md_getusername())); open_records(); /* * check for print-score option */ if (argc == 2 && strcmp(argv[1], "-s") == 0) { waswizard = TRUE; score(0, SCOREIT, 0); exit(0); } #ifdef NUMNET /* * Check for a network update */ if (argc == 2 && strcmp(argv[1], "-u") == 0) { unsigned long netread(); int errcheck, errors = 0; unsigned long amount; short monster; /* Read in the amount and monster values to pass to score */ amount = netread(&errcheck, sizeof(unsigned long), stdin); if (errcheck) errors++; monster = (short) netread(&errcheck, sizeof(short), stdin); if (errcheck) errors++; /* Now do the update if there were no errors */ if (errors) exit(1); else { score(amount, UPDATE, monster); exit(0); } } #endif #ifdef WIZARD /* * Check to see if he is a wizard */ if (argc >= 2 && argv[1][0] == '\0') if (strcmp(PASSWD, md_crypt(md_getpass("Wizard's password: "), "mT")) == 0) { wizard = TRUE; argv++; argc--; } #endif if (!wizard && !author() && !holiday()) { printf("Sorry, %s, but you can't play during working hours.\n", whoami); printf("Try again later.\n"); exit(1); } if (!wizard && !author() && too_much()) { printf("Sorry, %s, but the system is too loaded now.\n", whoami); printf("Try again later.\n"); exit(1); } #if NICE if (!wizard) nice(19); /* nice the max amount */ #endif if (use_savedir) { if (!restore(file_name, envp)) exit(1); } else { md_normaluser(); } if (argc == 2) if (!restore(argv[1], envp)) /* Note: restore will never return */ exit(1); dnum = (wizard && getenv("SEED") != NULL ? atoi(getenv("SEED")) : md_random_seed()); if (wizard) printf("Hello %s, welcome to dungeon #%d\n", whoami, dnum); else printf("Hello %s, just a moment while I dig the dungeon...\n", whoami); fflush(stdout); seed = dnum; md_srand(seed); #ifdef PC7300 /* Store static window parameters */ hardwindow = ioctl(0, WIOCGETD, &wdata); if (hardwindow >= 0) { /* We have a hardware window */ extern char **environ; /* Make sure our window is the right size */ oldwin = wdata; if ((wdata.uw_height / wdata.uw_vs) < 23 || (wdata.uw_width / wdata.uw_hs) < 75) { wdata.uw_width = 80 * wdata.uw_hs; wdata.uw_height = 24 * wdata.uw_vs; wdata.uw_x = 0; wdata.uw_y = wdata.uw_vs; wdata.uw_uflags = NBORDER; /* Make the change */ if (ioctl(1, WIOCSETD, &wdata) >= 0 && environ) { char **eptr, *tptr, *nptr, *newenv, *lptr = 0, *cptr = 0; int i, nlines = -1, ncols = -1, nlindig = 0, ncoldig = 0; struct utdata labelbuf; /* Save and change window-associated text */ for (i=0; i 85) cols = 85; if (lines > 24) lines = 24; if (lines < 23 || cols < 75) { /* give player a break if larger font used */ printf("\nERROR: screen size too small for rogue\n"); byebye(0); } /* * Now that we have cols and lines, we can update our window * structure for non-hardware windows. */ #ifdef PC7300 if (hardwindow < 0) { wdata.uw_x = 0; wdata.uw_y = 0; wdata.uw_width = COLS; wdata.uw_height = LINES; wdata.uw_uflags = 0; wdata.uw_hs = 1; wdata.uw_vs = 1; wdata.uw_baseline = 0; } #endif setup(); /* * Set up windows */ cw = newwin(lines, cols, 0, 0); mw = newwin(lines, cols, 0, 0); hw = newwin(lines, cols, 0, 0); msgw = newwin(4, cols, 0, 0); keypad(cw,TRUE); keypad(msgw,TRUE); init_player(); /* Roll up the rogue */ waswizard = wizard; #ifdef WIZARD /* A super wizard doesn't have to get equipped */ if (wizard && strcmp(getenv("SUPER"),"YES") == 0) { level = 1; new_level(NORMLEV); } else #endif new_level(STARTLEV); /* Draw current level */ /* * Start up daemons and fuses */ start_daemon(doctor, &player, AFTER); fuse(swander, NULL, WANDERTIME, AFTER); if (player.t_ctype == C_MAGICIAN || player.t_ctype == C_RANGER) fuse(spell_recovery, NULL, SPELLTIME, AFTER); if (player.t_ctype == C_DRUID || player.t_ctype == C_RANGER) fuse(chant_recovery, NULL, SPELLTIME, AFTER); if (player.t_ctype == C_CLERIC || player.t_ctype == C_PALADIN) fuse(prayer_recovery, NULL, SPELLTIME, AFTER); start_daemon(stomach, NULL, AFTER); if (player.t_ctype == C_THIEF || player.t_ctype == C_ASSASIN || player.t_ctype == C_MONK) start_daemon(trap_look, NULL, AFTER); /* Does this character have any special knowledge? */ switch (player.t_ctype) { case C_ASSASIN: /* Assassins automatically recognize poison */ p_know[P_POISON] = TRUE; } /* Choose a quest item */ quest_item = rnd(MAXRELIC); draw(cw); msg("You have been quested to retrieve the %s....", rel_magic[quest_item].mi_name); mpos = 0; playit(); } /* * endit: * Exit the program abnormally. */ void endit(int sig) { fatal("Ok, if you want to exit that badly, I'll have to allow it\n"); } /* * fatal: * Exit the program, printing a message. */ void fatal(char *s) { clear(); move(lines-2, 0); printw("%s", s); draw(stdscr); endwin(); #ifdef PC7300 endhardwin(); #endif printf("\n"); /* So the curser doesn't stop at the end of the line */ exit(0); } /* * rnd: * Pick a very random number. */ int rnd(int range) { return(range <= 0 ? 0 : md_rand() % range); } /* * roll: * roll a number of dice */ int roll(int number, int sides) { register int dtotal = 0; while(number--) dtotal += rnd(sides)+1; return dtotal; } # ifdef SIGTSTP /* * handle stop and start signals */ void tstp(int sig) { mvcur(0, cols - 1, lines - 1, 0); endwin(); fflush(stdout); kill(0, SIGTSTP); signal(SIGTSTP, tstp); raw(); noecho(); keypad(cw,1); keypad(msgw,1); clearok(curscr, TRUE); touchwin(cw); draw(cw); md_flushinp(); } # endif void setup(void) { #ifdef CHECKTIME int checkout(); if (!author()) { signal(SIGALRM, checkout); alarm(CHECKTIME * 60); } #endif /* #ifndef DUMP signal(SIGILL, bugkill); #ifdef SIGTRAP signal(SIGTRAP, bugkill); #endif #ifdef SIGIOT signal(SIGIOT, bugkill); #endif #ifdef SIGEMT signal(SIGEMT, bugkill); #endif signal(SIGFPE, bugkill); #ifdef SIGBUS signal(SIGBUS, bugkill); #endif signal(SIGSEGV, bugkill); #ifdef SIGSYS signal(SIGSYS, bugkill); #endif #ifdef SIGPIPE signal(SIGPIPE, bugkill); #endif #endif */ #ifdef SIGTSTP signal(SIGTSTP, tstp); #endif #ifdef SIGHUP signal(SIGHUP, auto_save); #endif signal(SIGTERM, auto_save); signal(SIGINT, quit); #ifdef SIGQUIT signal(SIGQUIT, endit); #endif raw(); /* Cbreak mode */ noecho(); /* Echo off */ nonl(); } void reopen_score(void) { if (scoreboard != NULL) fclose(scoreboard); scoreboard = fopen(score_file, "r+"); if (scoreboard == NULL && errno == ENOENT) scoreboard = fopen(score_file, "w+"); } void open_records(void) { if (scoreboard == NULL) reopen_score(); #ifdef LOGFILE if (logfile == NULL) logfile = fopen(LOGFILE, "a"); #endif return; } /* * playit: * The main loop of the program. Loop until the game is over, * refreshing things and looking at the proper times. */ void playit(void) { register char *opts; /* * parse environment declaration of options */ if ((opts = getenv("ROGUEOPTS")) != NULL) parse_opts(opts); player.t_oldpos = hero; oldrp = roomin(&hero); after = TRUE; command(); /* Command execution */ endit(0); } /* * see if the system is being used too much for this game */ bool too_much(void) { #if MAXPROCESSES if (loadav() > MAXPROCESSES) return(TRUE); #endif #if MAXUSERS if (ucount() > MAXUSERS) return(TRUE); #endif return(FALSE); } /* * author: * See if a user is an author of the program */ bool author(void) { switch (md_getuid()) { #if AUTHOR case AUTHOR: #endif case 0: /* always OK for root to play */ return TRUE; default: return FALSE; } } #if CHECKTIME static int num_checks = 0; /* times we've gone over in checkout() */ checkout() { static char *msgs[] = { "The system is too loaded for games. Please leave in %d minutes", "Please save your game. You have %d minutes", "This is your last chance. You had better leave in %d minutes", }; int checktime; signal(SIGALRM, checkout); if (!holiday() && !author()) { msg("Game time is over. Your game is being saved.\n\n"); auto_save(); /* NO RETURN */ } if (too_much()) { if (num_checks >= 3) fatal("You didn't listen, so now you are DEAD !!\n"); checktime = CHECKTIME / (num_checks + 1); chmsg(msgs[num_checks++], checktime); alarm(checktime * 60); } else { if (num_checks) { chmsg("The load has dropped. You have a reprieve."); num_checks = 0; } alarm(CHECKTIME * 60); } } /* * checkout()'s version of msg. If we are in the middle of a shell, do a * printf instead of a msg to avoid the refresh. */ void chmsg(char *fmt, int arg) { if (in_shell) { printf(fmt, arg); putchar('\n'); fflush(stdout); } else msg(fmt, arg); } #endif #ifdef MAXPROCESSES #include int loadav(void) { char *sarcmd = "sar -v | cut -c17-20 | tail -2"; char *gettycmd = "grep getty /etc/inittab | wc -l"; char sysbuffer[BUFSIZ]; char tempfile[50]; char inbuf[BUFSIZ]; int fd, nprocess, ngetty; sprintf(tempfile, "/tmp/rg%d", getpid()); sprintf(sysbuffer, "%s > %s", sarcmd, tempfile); if (system(sysbuffer) != 0) { debug ("system() call failed"); return (MAXPROCESSES - 1); } if ((fd = open(tempfile, O_RDONLY)) == -1) { debug ("open() call failed"); return (MAXPROCESSES - 1); } if (read(fd, inbuf, BUFSIZ) == -1) { debug ("read() call failed"); return (MAXPROCESSES - 1); } close(fd); sscanf(inbuf, "%d", &nprocess); sprintf(sysbuffer, "%s > %s", gettycmd, tempfile); if (system(sysbuffer) != 0) { debug ("system() call failed"); return (MAXPROCESSES - 1); } if ((fd = open(tempfile, O_RDONLY)) == -1) { debug ("open() call failed"); return (MAXPROCESSES - 1); } if (read(fd, inbuf, BUFSIZ) == -1) { debug ("read() call failed"); return (MAXPROCESSES - 1); } close(fd); sscanf(inbuf, "%d", &ngetty); unlink(tempfile); return(nprocess - ngetty); } #endif #ifdef MAXUSERS /* * ucount: * Count the number of people on the system */ #include #include struct utmp buf; int ucount(void) { reg struct utmp *up; reg FILE *utmp; reg int count; if ((utmp = fopen(UTMP, "r")) == NULL) return 0; up = &buf; count = 0; while (fread(up, 1, sizeof (*up), utmp) > 0) #ifdef BSD if (buf.ut_line[0] == 't') /* On a tty */ #else if (buf.ut_type == USER_PROCESS) #endif count++; fclose(utmp); return count; } #endif /* * holiday: * Returns TRUE when it is a good time to play rogue */ bool holiday(void) { #ifdef CHECKTIME long now; struct tm *localtime(); reg struct tm *ntime; time(&now); /* get the current time */ ntime = localtime(&now); if(ntime->tm_wday == 0 || ntime->tm_wday == 6) return TRUE; /* OK on Sat & Sun */ if(ntime->tm_hour < 8 || ntime->tm_hour >= 18) return TRUE; /* OK before 8AM & after 6PM */ if(ntime->tm_yday <= 7 || ntime->tm_yday >= 350) return TRUE; /* OK during Christmas */ return FALSE; /* All other times are bad */ #else return TRUE; #endif }