Annotation of early-roguelike/arogue7/main.c, Revision 1.1.1.1
1.1 rubenllo 1: /*
2: * main.c - setup code
3: *
4: * Advanced Rogue
5: * Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
6: * All rights reserved.
7: *
8: * Based on "Rogue: Exploring the Dungeons of Doom"
9: * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
10: * All rights reserved.
11: *
12: * See the file LICENSE.TXT for full copyright and licensing information.
13: */
14:
15: #include "curses.h"
16: #include <stdlib.h>
17: #include <string.h>
18: #include <signal.h>
19: #include <errno.h>
20: #ifdef BSD
21: #include <sys/time.h>
22: #else
23: #include <time.h>
24: #endif
25: #include "mach_dep.h"
26: #include "network.h"
27: #include "rogue.h"
28: #ifdef PC7300
29: #include "sys/window.h"
30: #include <ctype.h>
31: extern struct uwdata wdata, oldwin;
32: extern char oldtext[WTXTNUM][WTXTLEN];
33: #endif
34:
35: void open_records(void);
36: bool too_much(void);
37: bool author(void);
38: void chmsg(char *fmt, int arg);
39: #ifdef MAXPROCESSES
40: int loadav(void);
41: #endif
42: #ifdef MAXUSERS
43: int ucount(void);
44: #endif
45: bool holiday(void);
46:
47: int
48: main(int argc, char *argv[], char *envp[])
49: {
50: register char *env;
51: #ifdef PC7300
52: int hardwindow; /* Do we have a hardware window? */
53: #endif
54:
55: md_init();
56:
57: /*
58: * get home and options from environment
59: */
60:
61: strncpy(home, md_gethomedir(), LINELEN);
62:
63: /* Get default save file */
64: strcpy(file_name, home);
65: strcat(file_name, "arogue77.sav");
66:
67: /* Get default score file */
68: #ifdef SCOREFILE
69: strncpy(score_file, SCOREFILE, LINELEN);
70: score_file[LINELEN-1] = '\0';
71: #else
72: strcpy(score_file, md_getroguedir());
73:
74: if (*score_file)
75: strcat(score_file,"/");
76:
77: strcat(score_file,"arogue77.scr");
78: #endif
79:
80: #ifdef SAVEDIR
81: /* Check for common save location */
82: if (argc >= 3 && strcmp(argv[1], "-n") == 0)
83: {
84: strncpy(whoami, argv[2], 79);
85: whoami[79] = '\0';
86: use_savedir = TRUE;
87: if (LINELEN <= snprintf(file_name, LINELEN, "%s/%d-%s.ar7sav", SAVEDIR,
88: md_getuid(), whoami))
89: {
90: strcpy(file_name, "xrogue.sav");
91: use_savedir = FALSE;
92: }
93: }
94: #endif
95:
96: if ((env = getenv("ROGUEOPTS")) != NULL)
97: parse_opts(env);
98:
99: if (whoami[0] == '\0')
100: strucpy(whoami, md_getusername(), strlen(md_getusername()));
101:
102: open_records();
103:
104: /*
105: * check for print-score option
106: */
107: if (argc == 2 && strcmp(argv[1], "-s") == 0)
108: {
109: waswizard = TRUE;
110: score(0, SCOREIT, 0);
111: exit(0);
112: }
113:
114: #ifdef NUMNET
115: /*
116: * Check for a network update
117: */
118: if (argc == 2 && strcmp(argv[1], "-u") == 0) {
119: unsigned long netread();
120: int errcheck, errors = 0;
121: unsigned long amount;
122: short monster;
123:
124: /* Read in the amount and monster values to pass to score */
125: amount = netread(&errcheck, sizeof(unsigned long), stdin);
126: if (errcheck) errors++;
127:
128: monster = (short) netread(&errcheck, sizeof(short), stdin);
129: if (errcheck) errors++;
130:
131: /* Now do the update if there were no errors */
132: if (errors) exit(1);
133: else {
134: score(amount, UPDATE, monster);
135: exit(0);
136: }
137: }
138: #endif
139:
140: #ifdef WIZARD
141: /*
142: * Check to see if he is a wizard
143: */
144: if (argc >= 2 && argv[1][0] == '\0')
145: if (strcmp(PASSWD, md_crypt(md_getpass("Wizard's password: "), "mT")) == 0)
146: {
147: wizard = TRUE;
148: argv++;
149: argc--;
150: }
151: #endif
152:
153: if (!wizard && !author() && !holiday()) {
154: printf("Sorry, %s, but you can't play during working hours.\n", whoami);
155: printf("Try again later.\n");
156: exit(1);
157: }
158: if (!wizard && !author() && too_much()) {
159: printf("Sorry, %s, but the system is too loaded now.\n", whoami);
160: printf("Try again later.\n");
161: exit(1);
162: }
163:
164: #if NICE
165: if (!wizard)
166: nice(19); /* nice the max amount */
167: #endif
168:
169: if (use_savedir)
170: {
171: if (!restore(file_name, envp))
172: exit(1);
173: }
174: else
175: {
176: md_normaluser();
177: }
178: if (argc == 2)
179: if (!restore(argv[1], envp)) /* Note: restore will never return */
180: exit(1);
181: dnum = (wizard && getenv("SEED") != NULL ?
182: atoi(getenv("SEED")) :
183: md_random_seed());
184: if (wizard)
185: printf("Hello %s, welcome to dungeon #%d\n", whoami, dnum);
186: else
187: printf("Hello %s, just a moment while I dig the dungeon...\n", whoami);
188: fflush(stdout);
189: seed = dnum;
190: md_srand(seed);
191:
192: #ifdef PC7300
193: /* Store static window parameters */
194: hardwindow = ioctl(0, WIOCGETD, &wdata);
195: if (hardwindow >= 0) { /* We have a hardware window */
196: extern char **environ;
197:
198: /* Make sure our window is the right size */
199: oldwin = wdata;
200: if ((wdata.uw_height / wdata.uw_vs) < 23 ||
201: (wdata.uw_width / wdata.uw_hs) < 75) {
202: wdata.uw_width = 80 * wdata.uw_hs;
203: wdata.uw_height = 24 * wdata.uw_vs;
204: wdata.uw_x = 0;
205: wdata.uw_y = wdata.uw_vs;
206: wdata.uw_uflags = NBORDER;
207:
208: /* Make the change */
209: if (ioctl(1, WIOCSETD, &wdata) >= 0 && environ) {
210: char **eptr, *tptr, *nptr, *newenv, *lptr = 0, *cptr = 0;
211: int i, nlines = -1, ncols = -1, nlindig = 0, ncoldig = 0;
212: struct utdata labelbuf;
213:
214: /* Save and change window-associated text */
215: for (i=0; i<WTXTNUM; i++) {
216: labelbuf.ut_num = i;
217: ioctl(1, WIOCGETTEXT, &labelbuf);
218: strncpy(oldtext[i], labelbuf.ut_text, WTXTLEN - 1);
219: if (*labelbuf.ut_text) {
220: *labelbuf.ut_text = '\0';
221: ioctl(1, WIOCSETTEXT, &labelbuf);
222: }
223: }
224:
225: labelbuf.ut_num = WTXTLABEL;
226: strcpy(labelbuf.ut_text, "Advanced Rogue");
227: ioctl(1, WIOCSETTEXT, &labelbuf);
228:
229: /* We have to change the TERMCAP entry */
230: eptr = environ;
231: while (*eptr) {
232: if (strncmp(*eptr, "TERMCAP=", 8) == 0) break;
233: else eptr++;
234: }
235:
236: /* We found a TERMCAP entry */
237: if (*eptr) {
238: /* Search for li# and co# */
239: tptr = *eptr;
240: while (*tptr) {
241: switch (*tptr) {
242: case 'l':
243: if (nlines == -1 &&
244: strncmp(tptr, "li#", 3) == 0) {
245: tptr += 3;
246: lptr = tptr;
247: lines = atoi(tptr);
248: while (isdigit(*tptr)) {
249: nlindig++;;
250: tptr++;
251: }
252: }
253: else tptr++;
254: break;
255: case 'c':
256: if (ncols == -1 &&
257: strncmp(tptr, "co#", 3) == 0) {
258: tptr += 3;
259: cptr = tptr;
260: cols = atoi(tptr);
261: while (isdigit(*tptr)) {
262: ncoldig++;
263: tptr++;
264: }
265: }
266: else tptr++;
267: break;
268: default:
269: tptr++;
270: }
271: }
272:
273: /* Change the entry */
274: if (ncoldig != 2 || nlindig != 2) {
275: int length;
276:
277: /* Add in difference in num lengths plus NULL */
278: length = strlen(*eptr) - ncoldig - nlindig + 5;
279:
280: if (ncoldig == 0) length += 4; /* For :co# */
281: if (nlindig == 0) length += 4; /* For :li# */
282:
283: newenv = malloc(length);
284: tptr = *eptr;
285: nptr = newenv;
286:
287: if (nlindig == 0 || ncoldig == 0) {
288: /* Copy up to the first : */
289: while (*tptr && *tptr != ':') *nptr++ = *tptr++;
290:
291: /* Do we have to add a field? */
292: if (nlindig == 0) {
293: strcpy(nptr, ":li#24");
294: nptr += 6;
295: }
296: if (ncoldig == 0) {
297: strcpy(nptr, ":co#80");
298: nptr += 6;
299: }
300: }
301: while (*tptr) {
302: if (tptr == lptr) {
303: strcpy(nptr, "24");
304: nptr += 2;
305: tptr += nlindig;
306: }
307: else if (tptr == cptr) {
308: strcpy(nptr, "80");
309: nptr += 2;
310: tptr += ncoldig;
311: }
312: else *nptr++ = *tptr++;
313: }
314:
315: *nptr = '\0';
316:
317: /* Replace the old one */
318: free(*eptr);
319: *eptr = newenv;
320: }
321: else {
322: /* Just overwrite the old numbers */
323: *lptr++ = '2';
324: *lptr = '4';
325: *cptr++ = '8';
326: *cptr = '0';
327: }
328: }
329: }
330: }
331: }
332: #endif
333: init_things(); /* Set up probabilities of things */
334: init_colors(); /* Set up colors of potions */
335: init_stones(); /* Set up stone settings of rings */
336: init_materials(); /* Set up materials of wands */
337: initscr(); /* Start up cursor package */
338: init_names(); /* Set up names of scrolls */
339: init_misc(); /* Set up miscellaneous magic */
340: init_foods(); /* set up the food table */
341:
342: cols = COLS;
343: lines = LINES;
344: if (cols > 85) cols = 85;
345: if (lines > 24) lines = 24;
346: if (lines < 23 || cols < 75) { /* give player a break if larger font used */
347: printf("\nERROR: screen size too small for rogue\n");
348: byebye(0);
349: }
350:
351: /*
352: * Now that we have cols and lines, we can update our window
353: * structure for non-hardware windows.
354: */
355: #ifdef PC7300
356: if (hardwindow < 0) {
357: wdata.uw_x = 0;
358: wdata.uw_y = 0;
359: wdata.uw_width = COLS;
360: wdata.uw_height = LINES;
361: wdata.uw_uflags = 0;
362: wdata.uw_hs = 1;
363: wdata.uw_vs = 1;
364: wdata.uw_baseline = 0;
365: }
366: #endif
367: setup();
368: /*
369: * Set up windows
370: */
371: cw = newwin(lines, cols, 0, 0);
372: mw = newwin(lines, cols, 0, 0);
373: hw = newwin(lines, cols, 0, 0);
374: msgw = newwin(4, cols, 0, 0);
375: keypad(cw,TRUE);
376: keypad(msgw,TRUE);
377:
378: init_player(); /* Roll up the rogue */
379: waswizard = wizard;
380:
381: #ifdef WIZARD
382: /* A super wizard doesn't have to get equipped */
383: if (wizard && strcmp(getenv("SUPER"),"YES") == 0) {
384: level = 1;
385: new_level(NORMLEV);
386: }
387: else
388: #endif
389: new_level(STARTLEV); /* Draw current level */
390: /*
391: * Start up daemons and fuses
392: */
393: start_daemon(doctor, &player, AFTER);
394: fuse(swander, NULL, WANDERTIME, AFTER);
395: if (player.t_ctype == C_MAGICIAN || player.t_ctype == C_RANGER)
396: fuse(spell_recovery, NULL, SPELLTIME, AFTER);
397: if (player.t_ctype == C_DRUID || player.t_ctype == C_RANGER)
398: fuse(chant_recovery, NULL, SPELLTIME, AFTER);
399: if (player.t_ctype == C_CLERIC || player.t_ctype == C_PALADIN)
400: fuse(prayer_recovery, NULL, SPELLTIME, AFTER);
401: start_daemon(stomach, NULL, AFTER);
402: if (player.t_ctype == C_THIEF ||
403: player.t_ctype == C_ASSASIN ||
404: player.t_ctype == C_MONK)
405: start_daemon(trap_look, NULL, AFTER);
406:
407: /* Does this character have any special knowledge? */
408: switch (player.t_ctype) {
409: case C_ASSASIN:
410: /* Assassins automatically recognize poison */
411: p_know[P_POISON] = TRUE;
412: }
413:
414: /* Choose a quest item */
415: quest_item = rnd(MAXRELIC);
416: draw(cw);
417: msg("You have been quested to retrieve the %s....",
418: rel_magic[quest_item].mi_name);
419: mpos = 0;
420: playit();
421: }
422:
423: /*
424: * endit:
425: * Exit the program abnormally.
426: */
427:
428: void
429: endit(int sig)
430: {
431: fatal("Ok, if you want to exit that badly, I'll have to allow it\n");
432: }
433:
434: /*
435: * fatal:
436: * Exit the program, printing a message.
437: */
438:
439: void
440: fatal(char *s)
441: {
442: clear();
443: move(lines-2, 0);
444: printw("%s", s);
445: draw(stdscr);
446: endwin();
447: #ifdef PC7300
448: endhardwin();
449: #endif
450: printf("\n"); /* So the curser doesn't stop at the end of the line */
451: exit(0);
452: }
453:
454: /*
455: * rnd:
456: * Pick a very random number.
457: */
458: int
459: rnd(int range)
460: {
461: return(range <= 0 ? 0 : md_rand() % range);
462: }
463:
464: /*
465: * roll:
466: * roll a number of dice
467: */
468:
469: int
470: roll(int number, int sides)
471: {
472: register int dtotal = 0;
473:
474: while(number--)
475: dtotal += rnd(sides)+1;
476: return dtotal;
477: }
478: # ifdef SIGTSTP
479: /*
480: * handle stop and start signals
481: */
482: void
483: tstp(int sig)
484: {
485: mvcur(0, cols - 1, lines - 1, 0);
486: endwin();
487: fflush(stdout);
488: kill(0, SIGTSTP);
489: signal(SIGTSTP, tstp);
490: raw();
491: noecho();
492: keypad(cw,1);
493: keypad(msgw,1);
494: clearok(curscr, TRUE);
495: touchwin(cw);
496: draw(cw);
497: md_flushinp();
498: }
499: # endif
500:
501: void
502: setup(void)
503: {
504: #ifdef CHECKTIME
505: int checkout();
506:
507: if (!author()) {
508: signal(SIGALRM, checkout);
509: alarm(CHECKTIME * 60);
510: }
511: #endif
512: /*
513: #ifndef DUMP
514: signal(SIGILL, bugkill);
515: #ifdef SIGTRAP
516: signal(SIGTRAP, bugkill);
517: #endif
518: #ifdef SIGIOT
519: signal(SIGIOT, bugkill);
520: #endif
521: #ifdef SIGEMT
522: signal(SIGEMT, bugkill);
523: #endif
524: signal(SIGFPE, bugkill);
525: #ifdef SIGBUS
526: signal(SIGBUS, bugkill);
527: #endif
528: signal(SIGSEGV, bugkill);
529: #ifdef SIGSYS
530: signal(SIGSYS, bugkill);
531: #endif
532: #ifdef SIGPIPE
533: signal(SIGPIPE, bugkill);
534: #endif
535: #endif
536: */
537: #ifdef SIGTSTP
538: signal(SIGTSTP, tstp);
539: #endif
540:
541: #ifdef SIGHUP
542: signal(SIGHUP, auto_save);
543: #endif
544: signal(SIGTERM, auto_save);
545: signal(SIGINT, quit);
546: #ifdef SIGQUIT
547: signal(SIGQUIT, endit);
548: #endif
549: raw(); /* Cbreak mode */
550: noecho(); /* Echo off */
551: nonl();
552: }
553:
554: void
555: reopen_score(void)
556: {
557: if (scoreboard != NULL)
558: fclose(scoreboard);
559: scoreboard = fopen(score_file, "r+");
560: if (scoreboard == NULL && errno == ENOENT)
561: scoreboard = fopen(score_file, "w+");
562: }
563:
564: void
565: open_records(void)
566: {
567: if (scoreboard == NULL)
568: reopen_score();
569: #ifdef LOGFILE
570: if (logfile == NULL)
571: logfile = fopen(LOGFILE, "a");
572: #endif
573: return;
574: }
575:
576: /*
577: * playit:
578: * The main loop of the program. Loop until the game is over,
579: * refreshing things and looking at the proper times.
580: */
581:
582: void
583: playit(void)
584: {
585: register char *opts;
586:
587:
588: /*
589: * parse environment declaration of options
590: */
591: if ((opts = getenv("ROGUEOPTS")) != NULL)
592: parse_opts(opts);
593:
594:
595: player.t_oldpos = hero;
596: oldrp = roomin(&hero);
597: after = TRUE;
598: command(); /* Command execution */
599: endit(0);
600: }
601:
602: /*
603: * see if the system is being used too much for this game
604: */
605: bool
606: too_much(void)
607: {
608: #if MAXPROCESSES
609: if (loadav() > MAXPROCESSES)
610: return(TRUE);
611: #endif
612: #if MAXUSERS
613: if (ucount() > MAXUSERS)
614: return(TRUE);
615: #endif
616: return(FALSE);
617: }
618:
619: /*
620: * author:
621: * See if a user is an author of the program
622: */
623: bool
624: author(void)
625: {
626: switch (md_getuid()) {
627: #if AUTHOR
628: case AUTHOR:
629: #endif
630: case 0: /* always OK for root to play */
631: return TRUE;
632: default:
633: return FALSE;
634: }
635: }
636:
637:
638: #if CHECKTIME
639: static int num_checks = 0; /* times we've gone over in checkout() */
640:
641: checkout()
642: {
643: static char *msgs[] = {
644: "The system is too loaded for games. Please leave in %d minutes",
645: "Please save your game. You have %d minutes",
646: "This is your last chance. You had better leave in %d minutes",
647: };
648: int checktime;
649:
650: signal(SIGALRM, checkout);
651: if (!holiday() && !author()) {
652: msg("Game time is over. Your game is being saved.\n\n");
653: auto_save(); /* NO RETURN */
654: }
655: if (too_much()) {
656: if (num_checks >= 3)
657: fatal("You didn't listen, so now you are DEAD !!\n");
658: checktime = CHECKTIME / (num_checks + 1);
659: chmsg(msgs[num_checks++], checktime);
660: alarm(checktime * 60);
661: }
662: else {
663: if (num_checks) {
664: chmsg("The load has dropped. You have a reprieve.");
665: num_checks = 0;
666: }
667: alarm(CHECKTIME * 60);
668: }
669: }
670:
671: /*
672: * checkout()'s version of msg. If we are in the middle of a shell, do a
673: * printf instead of a msg to avoid the refresh.
674: */
675: void
676: chmsg(char *fmt, int arg)
677: {
678: if (in_shell) {
679: printf(fmt, arg);
680: putchar('\n');
681: fflush(stdout);
682: }
683: else
684: msg(fmt, arg);
685: }
686: #endif
687:
688: #ifdef MAXPROCESSES
689:
690: #include <fcntl.h>
691:
692: int
693: loadav(void)
694: {
695: char *sarcmd = "sar -v | cut -c17-20 | tail -2";
696: char *gettycmd = "grep getty /etc/inittab | wc -l";
697: char sysbuffer[BUFSIZ];
698: char tempfile[50];
699: char inbuf[BUFSIZ];
700: int fd, nprocess, ngetty;
701:
702: sprintf(tempfile, "/tmp/rg%d", getpid());
703: sprintf(sysbuffer, "%s > %s", sarcmd, tempfile);
704: if (system(sysbuffer) != 0) {
705: debug ("system() call failed");
706: return (MAXPROCESSES - 1);
707: }
708: if ((fd = open(tempfile, O_RDONLY)) == -1) {
709: debug ("open() call failed");
710: return (MAXPROCESSES - 1);
711: }
712: if (read(fd, inbuf, BUFSIZ) == -1) {
713: debug ("read() call failed");
714: return (MAXPROCESSES - 1);
715: }
716: close(fd);
717: sscanf(inbuf, "%d", &nprocess);
718: sprintf(sysbuffer, "%s > %s", gettycmd, tempfile);
719: if (system(sysbuffer) != 0) {
720: debug ("system() call failed");
721: return (MAXPROCESSES - 1);
722: }
723: if ((fd = open(tempfile, O_RDONLY)) == -1) {
724: debug ("open() call failed");
725: return (MAXPROCESSES - 1);
726: }
727: if (read(fd, inbuf, BUFSIZ) == -1) {
728: debug ("read() call failed");
729: return (MAXPROCESSES - 1);
730: }
731: close(fd);
732: sscanf(inbuf, "%d", &ngetty);
733: unlink(tempfile);
734: return(nprocess - ngetty);
735: }
736: #endif
737:
738: #ifdef MAXUSERS
739: /*
740: * ucount:
741: * Count the number of people on the system
742: */
743: #include <sys/types.h>
744: #include <utmp.h>
745: struct utmp buf;
746:
747: int
748: ucount(void)
749: {
750: reg struct utmp *up;
751: reg FILE *utmp;
752: reg int count;
753:
754: if ((utmp = fopen(UTMP, "r")) == NULL)
755: return 0;
756:
757: up = &buf;
758: count = 0;
759: while (fread(up, 1, sizeof (*up), utmp) > 0)
760: #ifdef BSD
761: if (buf.ut_line[0] == 't') /* On a tty */
762: #else
763: if (buf.ut_type == USER_PROCESS)
764: #endif
765: count++;
766: fclose(utmp);
767: return count;
768: }
769: #endif
770:
771: /*
772: * holiday:
773: * Returns TRUE when it is a good time to play rogue
774: */
775: bool
776: holiday(void)
777: {
778: #ifdef CHECKTIME
779: long now;
780: struct tm *localtime();
781: reg struct tm *ntime;
782:
783:
784: time(&now); /* get the current time */
785: ntime = localtime(&now);
786: if(ntime->tm_wday == 0 || ntime->tm_wday == 6)
787: return TRUE; /* OK on Sat & Sun */
788: if(ntime->tm_hour < 8 || ntime->tm_hour >= 18)
789: return TRUE; /* OK before 8AM & after 6PM */
790: if(ntime->tm_yday <= 7 || ntime->tm_yday >= 350)
791: return TRUE; /* OK during Christmas */
792: return FALSE; /* All other times are bad */
793: #else
794: return TRUE;
795: #endif
796: }
CVSweb