Annotation of early-roguelike/arogue5/main.c, Revision 1.1.1.1
1.1 rubenllo 1: /*
2: * Rogue
3: *
4: * Advanced Rogue
5: * Copyright (C) 1984, 1985 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 <fcntl.h>
19: #include <sys/stat.h>
20: #include <limits.h>
21: #include <signal.h>
22: #include <time.h>
23: #include <errno.h>
24: #include "mach_dep.h"
25: #include "network.h"
26: #include "rogue.h"
27:
28: #ifdef CHECKTIME
29: static int num_checks; /* times we've gone over in checkout() */
30: #endif
31:
32: /*
33: * fruits that you get at startup
34: */
35: static char *funfruit[] = {
36: "candleberry", "caprifig", "dewberry", "elderberry",
37: "gooseberry", "guanabana", "hagberry", "ilama",
38: "imbu", "jaboticaba", "jujube", "litchi",
39: "mombin", "pitanga", "prickly pear", "rambutan",
40: "sapodilla", "soursop", "sweetsop", "whortleberry",
41: "jellybean", "apple", "strawberry", "blueberry",
42: "peach", "banana"
43: };
44: #define NFRUIT (sizeof(funfruit) / sizeof (char *))
45:
46: void open_records(void);
47: bool holiday(void);
48:
49: int
50: main(int argc, char *argv[], char *envp[])
51: {
52: register char *env;
53: char *roguedir;
54:
55: roguedir = md_getroguedir();
56: md_init();
57:
58: /*
59: * get home and options from environment
60: */
61: strncpy(home,md_gethomedir(),LINELEN);
62:
63: #ifdef SAVEDIR
64: if (argc >= 3 && !strcmp(argv[1], "-n")) {
65: use_savedir = TRUE;
66: strncpy(whoami, argv[2], LINELEN);
67: whoami[LINELEN - 1] = '\0';
68: if (snprintf(file_name, 256, "%s/%d-%s.ar5sav", SAVEDIR,
69: md_getuid(), whoami) >= 256)
70: {
71: /* The name is too long */
72: use_savedir = FALSE;
73: }
74: }
75: #endif
76: /* Get default save file */
77: if (!use_savedir) {
78: strcpy(file_name, home);
79: strcat(file_name, "arogue58.sav");
80: }
81:
82: #ifdef SCOREFILE
83: strncpy(score_file, SCOREFILE, LINELEN);
84: score_file[LINELEN - 1] = '\0';
85: #else
86: /* Get default score file */
87: strcpy(score_file, roguedir);
88:
89: if (*score_file)
90: strcat(score_file,"/");
91:
92: strcat(score_file, "arogue58.scr");
93: #endif
94:
95: if ((env = getenv("ROGUEOPTS")) != NULL)
96: parse_opts(env);
97:
98: if (!use_savedir && whoami[0] == '\0')
99: strucpy(whoami, md_getusername(), strlen(md_getusername()));
100:
101: if (env == NULL || fruit[0] == '\0') {
102: md_srand(md_random_seed());
103: strcpy(fruit, funfruit[rnd(NFRUIT)]);
104: }
105:
106: open_records();
107: if (!use_savedir)
108: md_normaluser();
109:
110: /*
111: * check for print-score option
112: */
113: if (argc == 2 && strcmp(argv[1], "-s") == 0)
114: {
115: waswizard = TRUE;
116: score(0, SCOREIT, 0);
117: exit(0);
118: }
119:
120: #ifdef NUMNET
121: /*
122: * Check for a network update
123: */
124: if (argc == 2 && strcmp(argv[1], "-u") == 0) {
125: int errcheck, errors = 0;
126: unsigned long amount;
127: short monster;
128:
129: /* Read in the amount and monster values to pass to score */
130: amount = netread(&errcheck, sizeof(unsigned long), stdin);
131: if (errcheck) errors++;
132:
133: monster = (short) netread(&errcheck, sizeof(short), stdin);
134: if (errcheck) errors++;
135:
136: /* Now do the update if there were no errors */
137: if (errors) exit(1);
138: else {
139: score(amount, UPDATE, monster);
140: exit(0);
141: }
142: }
143: #endif
144:
145: #ifdef WIZARD
146: /*
147: * Check to see if he is a wizard
148: */
149: if (argc >= 2 && argv[1][0] == '\0')
150: if (strcmp(PASSWD, md_crypt(md_getpass("Wizard's password: "), "Si")) == 0)
151: {
152: printf("Hail Mighty Wizard\n");
153: wizard = TRUE;
154: argv++;
155: argc--;
156: }
157: #endif
158:
159: #if MAXLOAD|MAXUSERS
160: if (too_much() && !wizard && !author())
161: {
162: printf("Sorry, %s, but the system is too loaded now.\n", whoami);
163: printf("Try again later. Meanwhile, why not enjoy a%s %s?\n",
164: vowelstr(fruit), fruit);
165: exit(1);
166: }
167: #endif
168: if (use_savedir)
169: {
170: /* Try to restore from file_name first. */
171: if (!restore(file_name, envp))
172: exit(1);
173: /* If restore() returns true, there is no such saved game.
174: So start a new one. */
175: }
176: else if (argc == 2)
177: if (!restore(argv[1], envp)) /* Note: restore will never return */
178: exit(1);
179: dnum = (wizard && getenv("SEED") != NULL ?
180: atoi(getenv("SEED")) :
181: md_random_seed());
182: if (wizard)
183: printf("Hello %s, welcome to dungeon #%d\n", whoami, dnum);
184: else
185: printf("Hello %s, just a moment while I dig the dungeon...\n", whoami);
186: fflush(stdout);
187: seed = dnum;
188: md_srand(seed);
189:
190: init_things(); /* Set up probabilities of things */
191: init_colors(); /* Set up colors of potions */
192: init_stones(); /* Set up stone settings of rings */
193: init_materials(); /* Set up materials of wands */
194: initscr(); /* Start up cursor package */
195: init_names(); /* Set up names of scrolls */
196: init_misc(); /* Set up miscellaneous magic */
197: if (LINES < 24 || COLS < 80) {
198: printf("\nERROR: screen size to small for rogue\n");
199: byebye(-1);
200: }
201:
202: if (!use_savedir) {
203: if ((*whoami == '\0') || (strcmp(whoami,"dosuser")==0))
204: {
205: echo();
206: mvaddstr(23,2,"Rogue's Name? ");
207: wgetnstr(stdscr,whoami,LINELEN);
208: noecho();
209: }
210:
211: if (*whoami == '\0')
212: strcpy(whoami,"Rodney");
213: }
214:
215: setup();
216: /*
217: * Set up windows
218: */
219: cw = newwin(LINES, COLS, 0, 0);
220: mw = newwin(LINES, COLS, 0, 0);
221: hw = newwin(LINES, COLS, 0, 0);
222: msgw = newwin(4, COLS, 0, 0);
223: keypad(cw,1);
224: keypad(msgw,1);
225:
226: init_player(); /* Roll up the rogue */
227: waswizard = wizard;
228: new_level(NORMLEV); /* Draw current level */
229: /*
230: * Start up daemons and fuses
231: */
232: start_daemon(doctor, &player, AFTER);
233: fuse(swander, 0, WANDERTIME, AFTER);
234: start_daemon(stomach, 0, AFTER);
235: start_daemon(runners, 0, AFTER);
236: if (player.t_ctype == C_THIEF)
237: start_daemon(trap_look, 0, AFTER);
238:
239: /* Choose a quest item */
240: quest_item = rnd(MAXRELIC);
241: msg("You have been quested to retrieve the %s....",
242: rel_magic[quest_item].mi_name);
243: mpos = 0;
244: playit();
245: }
246:
247: void
248: reopen_score(void)
249: {
250: if (scoreboard != NULL)
251: fclose(scoreboard);
252: scoreboard = fopen(score_file, "r+");
253: if (scoreboard == NULL && errno == ENOENT) {
254: scoreboard = fopen(score_file, "w+");
255: }
256: }
257:
258:
259: void
260: open_records(void)
261: {
262: if (scoreboard == NULL)
263: reopen_score();
264: #ifdef LOGFILE
265: if (logfile == NULL)
266: logfile = fopen(LOGFILE, "a");
267: #endif
268: return;
269: }
270:
271: /*
272: * endit:
273: * Exit the program abnormally.
274: */
275: void
276: endit(int sig)
277: {
278: NOOP(sig);
279:
280: fatal("Ok, if you want to exit that badly, I'll have to allow it\n");
281: }
282:
283: /*
284: * fatal:
285: * Exit the program, printing a message.
286: */
287:
288: void
289: fatal(char *s)
290: {
291: clear();
292: move(LINES-2, 0);
293: printw("%s", s);
294: draw(stdscr);
295: endwin();
296: printf("\n"); /* So the cursor doesn't stop at the end of the line */
297: exit(0);
298: }
299:
300: /*
301: * rnd:
302: * Pick a very random number.
303: */
304:
305: int
306: rnd(int range)
307: {
308: return(range == 0 ? 0 : md_rand() % range);
309: }
310:
311: /*
312: * roll:
313: * roll a number of dice
314: */
315:
316: int
317: roll(int number, int sides)
318: {
319: register int dtotal = 0;
320:
321: while(number--)
322: dtotal += rnd(sides)+1;
323: return dtotal;
324: }
325: # ifdef SIGTSTP
326: /*
327: * handle stop and start signals
328: */
329: void
330: tstp(int a)
331: {
332: mvcur(0, COLS - 1, LINES - 1, 0);
333: endwin();
334: fflush(stdout);
335: kill(0, SIGTSTP);
336: signal(SIGTSTP, tstp);
337: raw();
338: noecho();
339: keypad(cw,1);
340: clearok(curscr, TRUE);
341: touchwin(cw);
342: draw(cw);
343: md_flushinp();
344: }
345: # endif
346:
347: void
348: setup(void)
349: {
350: #ifdef CHECKTIME
351: void checkout();
352: #endif
353:
354: #ifndef DUMP
355: #ifdef SIGHUP
356: signal(SIGHUP, auto_save);
357: #endif
358: signal(SIGILL, bugkill);
359: #ifdef SIGTRAP
360: signal(SIGTRAP, bugkill);
361: #endif
362: #ifdef SIGIOT
363: signal(SIGIOT, bugkill);
364: #endif
365: #if 0
366: signal(SIGEMT, bugkill);
367: signal(SIGFPE, bugkill);
368: signal(SIGBUS, bugkill);
369: signal(SIGSEGV, bugkill);
370: signal(SIGSYS, bugkill);
371: signal(SIGPIPE, bugkill);
372: #endif
373: signal(SIGTERM, auto_save);
374: #endif
375:
376: signal(SIGINT, quit);
377: #ifndef DUMP
378: #ifdef SIGQUIT
379: signal(SIGQUIT, endit);
380: #endif
381: #endif
382: #ifdef SIGTSTP
383: signal(SIGTSTP, tstp);
384: #endif
385: #ifdef CHECKTIME
386: if (!author())
387: {
388: signal(SIGALRM, checkout);
389: alarm(CHECKTIME * 60);
390: num_checks = 0;
391: }
392: #endif
393: nonl();
394: crmode(); /* Cbreak mode */
395: noecho(); /* Echo off */
396: }
397:
398: /*
399: * playit:
400: * The main loop of the program. Loop until the game is over,
401: * refreshing things and looking at the proper times.
402: */
403:
404: void
405: playit(void)
406: {
407: register char *opts;
408:
409:
410: /*
411: * parse environment declaration of options
412: */
413: if ((opts = getenv("ROGUEOPTS")) != NULL)
414: parse_opts(opts);
415:
416:
417: player.t_oldpos = hero;
418: oldrp = roomin(&hero);
419: after = TRUE;
420: while (playing)
421: command(); /* Command execution */
422: endit(0);
423: }
424:
425: #if MAXLOAD|MAXUSERS
426: /*
427: * see if the system is being used too much for this game
428: */
429: bool
430: too_much(void)
431: {
432: #ifdef MAXLOAD
433: double avec[3];
434: #endif
435:
436: #ifdef MAXLOAD
437: loadav(avec);
438: return (avec[2] > (MAXLOAD / 10.0));
439: #else
440: return (ucount() > MAXUSERS);
441: #endif
442: }
443: #endif
444:
445: /*
446: * author:
447: * See if a user is an author of the program
448: */
449: bool
450: author(void)
451: {
452: switch (md_getuid()) {
453: #if AUTHOR
454: case AUTHOR:
455: #endif
456: case 0:
457: return TRUE;
458: default:
459: return FALSE;
460: }
461: }
462:
463:
464: #ifdef CHECKTIME
465: /*
466: * checkout()'s version of msg. If we are in the middle of a shell, do a
467: * printf instead of a msg to avoid the refresh.
468: */
469: void
470: chmsg(char *fmt, int arg)
471: {
472: if (in_shell) {
473: printf(fmt, arg);
474: putchar('\n');
475: fflush(stdout);
476: }
477: else
478: msg(fmt, arg);
479: }
480:
481: void
482: checkout(void)
483: {
484: static char *msgs[] = {
485: "The system is too loaded for games. Please leave in %d minutes",
486: "Please save your game. You have %d minutes",
487: "This is your last chance. You had better leave in %d minutes",
488: };
489: int checktime;
490:
491: signal(SIGALRM, checkout);
492: if (!holiday() && !author()) {
493: wclear(cw);
494: mvwaddstr(cw, LINES / 2, 0,
495: "Game time is over. Your game is being saved.\n\n");
496: draw(cw);
497: auto_save(); /* NO RETURN */
498: }
499: if (too_much()) {
500: if (num_checks >= 3)
501: fatal("You didn't listen, so now you are DEAD !!\n");
502: checktime = CHECKTIME / (num_checks + 1);
503: chmsg(msgs[num_checks++], checktime);
504: alarm(checktime * 60);
505: }
506: else {
507: if (num_checks) {
508: chmsg("The load has dropped. You have a reprieve.");
509: num_checks = 0;
510: }
511: alarm(CHECKTIME * 60);
512: }
513: }
514: #endif
515:
516: #ifdef LOADAV
517:
518: #include <nlist.h>
519:
520: struct nlist avenrun =
521: {
522: "_avenrun"
523: };
524:
525: void
526: loadav(double *avg)
527: {
528: reg int kmem;
529:
530: if ((kmem = open("/dev/kmem", 0)) < 0)
531: goto bad;
532: nlist(NAMELIST, &avenrun);
533: if (avenrun.n_type == 0) {
534: bad:
535: avg[0] = avg[1] = avg[2] = 0.0;
536: return;
537: }
538: lseek(kmem, (long) avenrun.n_value, 0);
539: read(kmem, avg, 3 * sizeof (double));
540: }
541: #endif
542:
543: #ifdef UCOUNT
544: /*
545: * ucount:
546: * Count the number of people on the system
547: */
548: #include <sys/types.h>
549: #include <utmp.h>
550: struct utmp buf;
551: int
552: ucount(void)
553: {
554: reg struct utmp *up;
555: reg FILE *utmp;
556: reg int count;
557:
558: if ((utmp = fopen(UTMP, "r")) == NULL)
559: return 0;
560:
561: up = &buf;
562: count = 0;
563: while (fread(up, 1, sizeof (*up), utmp) > 0)
564: if (buf.ut_type == USER_PROCESS)
565: count++;
566: fclose(utmp);
567: return count;
568: }
569: #endif
570:
571: /*
572: * holiday:
573: * Returns TRUE when it is a good time to play rogue
574: */
575: bool
576: holiday(void)
577: {
578: time_t now;
579: struct tm *localtime();
580: reg struct tm *ntime;
581:
582: time(&now); /* get the current time */
583: ntime = localtime(&now);
584: if(ntime->tm_wday == 0 || ntime->tm_wday == 6)
585: return TRUE; /* OK on Sat & Sun */
586: if(ntime->tm_hour < 8 || ntime->tm_hour >= 17)
587: return TRUE; /* OK before 8AM & after 5PM */
588: if(ntime->tm_yday <= 7 || ntime->tm_yday >= 350)
589: return TRUE; /* OK during Christmas */
590: #if 0 /* not for now */
591: if (access("/usr/tmp/.ryes",0) == 0)
592: return TRUE; /* if author permission */
593: #endif
594:
595: return FALSE; /* All other times are bad */
596: }
CVSweb