|
|
1.1 root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
2: /* hack.main.c - version 1.0.3 */
3:
4: #include <stdio.h>
5: #include <signal.h>
6: #include "hack.h"
7:
8: #ifdef QUEST
9: #define gamename "quest"
10: #else
11: #define gamename "hack"
12: #endif QUEST
13:
14: extern char *getlogin(), *getenv();
15: extern char plname[PL_NSIZ], pl_character[PL_CSIZ];
16: extern struct permonst mons[CMNUM+2];
17: extern char genocided[], fut_geno[];
18:
19: int (*afternmv)();
20: int (*occupation)();
21: char *occtxt; /* defined when occupation != NULL */
22:
23: int done1();
24: int hangup();
25:
26: int hackpid; /* current pid */
27: int locknum; /* max num of players */
28: #ifdef DEF_PAGER
29: char *catmore; /* default pager */
30: #endif DEF_PAGER
31: char SAVEF[PL_NSIZ + 11] = "save/"; /* save/99999player */
32: char *hname; /* name of the game (argv[0] of call) */
33: char obuf[BUFSIZ]; /* BUFSIZ is defined in stdio.h */
34:
35: extern char *nomovemsg;
36: extern long wailmsg;
37:
38: main(argc,argv)
39: int argc;
40: char *argv[];
41: {
42: register int fd;
43: #ifdef CHDIR
44: register char *dir;
45: #endif CHDIR
46:
47: hname = argv[0];
48: hackpid = getpid();
49:
50: #ifdef CHDIR /* otherwise no chdir() */
51: /*
52: * See if we must change directory to the playground.
53: * (Perhaps hack runs suid and playground is inaccessible
54: * for the player.)
55: * The environment variable HACKDIR is overridden by a
56: * -d command line option (must be the first option given)
57: */
58:
59: dir = getenv("HACKDIR");
60: if(argc > 1 && !strncmp(argv[1], "-d", 2)) {
61: argc--;
62: argv++;
63: dir = argv[0]+2;
64: if(*dir == '=' || *dir == ':') dir++;
65: if(!*dir && argc > 1) {
66: argc--;
67: argv++;
68: dir = argv[0];
69: }
70: if(!*dir)
71: error("Flag -d must be followed by a directory name.");
72: }
73: #endif CHDIR
74:
75: /*
76: * Who am i? Algorithm: 1. Use name as specified in HACKOPTIONS
77: * 2. Use $USER or $LOGNAME (if 1. fails)
78: * 3. Use getlogin() (if 2. fails)
79: * The resulting name is overridden by command line options.
80: * If everything fails, or if the resulting name is some generic
81: * account like "games", "play", "player", "hack" then eventually
82: * we'll ask him.
83: * Note that we trust him here; it is possible to play under
84: * somebody else's name.
85: */
86: { register char *s;
87:
88: initoptions();
89: if(!*plname && (s = getenv("USER")))
90: (void) strncpy(plname, s, sizeof(plname)-1);
91: if(!*plname && (s = getenv("LOGNAME")))
92: (void) strncpy(plname, s, sizeof(plname)-1);
93: if(!*plname && (s = getlogin()))
94: (void) strncpy(plname, s, sizeof(plname)-1);
95: }
96:
97: /*
98: * Now we know the directory containing 'record' and
99: * may do a prscore().
100: */
101: if(argc > 1 && !strncmp(argv[1], "-s", 2)) {
102: #ifdef CHDIR
103: chdirx(dir,0);
104: #endif CHDIR
105: prscore(argc, argv);
106: exit(0);
107: }
108:
109: /*
110: * It seems he really wants to play.
111: * Remember tty modes, to be restored on exit.
112: */
113: gettty();
114: setbuf(stdout,obuf);
115: setrandom();
116: startup();
117: cls();
118: u.uhp = 1; /* prevent RIP on early quits */
119: u.ux = FAR; /* prevent nscr() */
120: (void) signal(SIGHUP, hangup);
121:
122: /*
123: * Find the creation date of this game,
124: * so as to avoid restoring outdated savefiles.
125: */
126: gethdate(hname);
127:
128: /*
129: * We cannot do chdir earlier, otherwise gethdate will fail.
130: */
131: #ifdef CHDIR
132: chdirx(dir,1);
133: #endif CHDIR
134:
135: /*
136: * Process options.
137: */
138: while(argc > 1 && argv[1][0] == '-'){
139: argv++;
140: argc--;
141: switch(argv[0][1]){
142: #ifdef WIZARD
143: case 'D':
144: /* if(!strcmp(getlogin(), WIZARD)) */
145: wizard = TRUE;
146: /* else
147: printf("Sorry.\n"); */
148: break;
149: #endif WIZARD
150: #ifdef NEWS
151: case 'n':
152: flags.nonews = TRUE;
153: break;
154: #endif NEWS
155: case 'u':
156: if(argv[0][2])
157: (void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
158: else if(argc > 1) {
159: argc--;
160: argv++;
161: (void) strncpy(plname, argv[0], sizeof(plname)-1);
162: } else
163: printf("Player name expected after -u\n");
164: break;
165: default:
166: /* allow -T for Tourist, etc. */
167: (void) strncpy(pl_character, argv[0]+1,
168: sizeof(pl_character)-1);
169:
170: /* printf("Unknown option: %s\n", *argv); */
171: }
172: }
173:
174: if(argc > 1)
175: locknum = atoi(argv[1]);
176: #ifdef MAX_NR_OF_PLAYERS
177: if(!locknum || locknum > MAX_NR_OF_PLAYERS)
178: locknum = MAX_NR_OF_PLAYERS;
179: #endif MAX_NR_OF_PLAYERS
180: #ifdef DEF_PAGER
181: if(!(catmore = getenv("HACKPAGER")) && !(catmore = getenv("PAGER")))
182: catmore = DEF_PAGER;
183: #endif DEF_PAGER
184: #ifdef MAIL
185: getmailstatus();
186: #endif MAIL
187: #ifdef WIZARD
188: if(wizard) (void) strcpy(plname, "wizard"); else
189: #endif WIZARD
190: if(!*plname || !strncmp(plname, "player", 4)
191: || !strncmp(plname, "games", 4))
192: askname();
193: plnamesuffix(); /* strip suffix from name; calls askname() */
194: /* again if suffix was whole name */
195: /* accepts any suffix */
196: #ifdef WIZARD
197: if(!wizard) {
198: #endif WIZARD
199: /*
200: * check for multiple games under the same name
201: * (if !locknum) or check max nr of players (otherwise)
202: */
203: (void) signal(SIGQUIT,SIG_IGN);
204: (void) signal(SIGINT,SIG_IGN);
205: if(!locknum)
206: (void) strcpy(lock,plname);
207: getlock(); /* sets lock if locknum != 0 */
208: #ifdef WIZARD
209: } else {
210: register char *sfoo;
211: (void) strcpy(lock,plname);
212: if(sfoo = getenv("MAGIC"))
213: while(*sfoo) {
214: switch(*sfoo++) {
215: case 'n': (void) srandom(*sfoo++);
216: break;
217: }
218: }
219: if(sfoo = getenv("GENOCIDED")){
220: if(*sfoo == '!'){
221: register struct permonst *pm = mons;
222: register char *gp = genocided;
223:
224: while(pm < mons+CMNUM+2){
225: if(!index(sfoo, pm->mlet))
226: *gp++ = pm->mlet;
227: pm++;
228: }
229: *gp = 0;
230: } else
231: (void) strcpy(genocided, sfoo);
232: (void) strcpy(fut_geno, genocided);
233: }
234: }
235: #endif WIZARD
236: setftty();
237: (void) sprintf(SAVEF, "save/%d%s", getuid(), plname);
238: regularize(SAVEF+5); /* avoid . or / in name */
239: if((fd = open(SAVEF,0)) >= 0 &&
240: (uptodate(fd) || unlink(SAVEF) == 666)) {
241: (void) signal(SIGINT,done1);
242: pline("Restoring old save file...");
243: (void) fflush(stdout);
244: if(!dorecover(fd))
245: goto not_recovered;
246: pline("Hello %s, welcome to %s!", plname, gamename);
247: flags.move = 0;
248: } else {
249: not_recovered:
250: fobj = fcobj = invent = 0;
251: fmon = fallen_down = 0;
252: ftrap = 0;
253: fgold = 0;
254: flags.ident = 1;
255: init_objects();
256: u_init();
257:
258: (void) signal(SIGINT,done1);
259: mklev();
260: u.ux = xupstair;
261: u.uy = yupstair;
262: (void) inshop();
263: setsee();
264: flags.botlx = 1;
265: makedog();
266: { register struct monst *mtmp;
267: if(mtmp = m_at(u.ux, u.uy)) mnexto(mtmp); /* riv05!a3 */
268: }
269: seemons();
270: #ifdef NEWS
271: if(flags.nonews || !readnews())
272: /* after reading news we did docrt() already */
273: #endif NEWS
274: docrt();
275:
276: /* give welcome message before pickup messages */
277: pline("Hello %s, welcome to %s!", plname, gamename);
278:
279: pickup(1);
280: read_engr_at(u.ux,u.uy);
281: flags.move = 1;
282: }
283:
284: flags.moonphase = phase_of_the_moon();
285: if(flags.moonphase == FULL_MOON) {
286: pline("You are lucky! Full moon tonight.");
287: u.uluck++;
288: } else if(flags.moonphase == NEW_MOON) {
289: pline("Be careful! New moon tonight.");
290: }
291:
292: initrack();
293:
294: for(;;) {
295: if(flags.move) { /* actual time passed */
296:
297: settrack();
298:
299: if(moves%2 == 0 ||
300: (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) {
301: extern struct monst *makemon();
302: movemon();
303: if(!rn2(70))
304: (void) makemon((struct permonst *)0, 0, 0);
305: }
306: if(Glib) glibr();
307: timeout();
308: ++moves;
309: if(flags.time) flags.botl = 1;
310: if(u.uhp < 1) {
311: pline("You die...");
312: done("died");
313: }
314: if(u.uhp*10 < u.uhpmax && moves-wailmsg > 50){
315: wailmsg = moves;
316: if(u.uhp == 1)
317: pline("You hear the wailing of the Banshee...");
318: else
319: pline("You hear the howling of the CwnAnnwn...");
320: }
321: if(u.uhp < u.uhpmax) {
322: if(u.ulevel > 9) {
323: if(Regeneration || !(moves%3)) {
324: flags.botl = 1;
325: u.uhp += rnd((int) u.ulevel-9);
326: if(u.uhp > u.uhpmax)
327: u.uhp = u.uhpmax;
328: }
329: } else if(Regeneration ||
330: (!(moves%(22-u.ulevel*2)))) {
331: flags.botl = 1;
332: u.uhp++;
333: }
334: }
335: if(Teleportation && !rn2(85)) tele();
336: if(Searching && multi >= 0) (void) dosearch();
337: gethungry();
338: invault();
339: amulet();
340: }
341: if(multi < 0) {
342: if(!++multi){
343: pline(nomovemsg ? nomovemsg :
344: "You can move again.");
345: nomovemsg = 0;
346: if(afternmv) (*afternmv)();
347: afternmv = 0;
348: }
349: }
350:
351: find_ac();
352: #ifndef QUEST
353: if(!flags.mv || Blind)
354: #endif QUEST
355: {
356: seeobjs();
357: seemons();
358: nscr();
359: }
360: if(flags.botl || flags.botlx) bot();
361:
362: flags.move = 1;
363:
364: if(multi >= 0 && occupation) {
365: if(monster_nearby())
366: stop_occupation();
367: else if ((*occupation)() == 0)
368: occupation = 0;
369: continue;
370: }
371:
372: if(multi > 0) {
373: #ifdef QUEST
374: if(flags.run >= 4) finddir();
375: #endif QUEST
376: lookaround();
377: if(!multi) { /* lookaround may clear multi */
378: flags.move = 0;
379: continue;
380: }
381: if(flags.mv) {
382: if(multi < COLNO && !--multi)
383: flags.mv = flags.run = 0;
384: domove();
385: } else {
386: --multi;
387: rhack(save_cm);
388: }
389: } else if(multi == 0) {
390: #ifdef MAIL
391: ckmailstatus();
392: #endif MAIL
393: rhack((char *) 0);
394: }
395: if(multi && multi%7 == 0)
396: (void) fflush(stdout);
397: }
398: }
399:
400: glo(foo)
401: register foo;
402: {
403: /* construct the string xlock.n */
404: register char *tf;
405:
406: tf = lock;
407: while(*tf && *tf != '.') tf++;
408: (void) sprintf(tf, ".%d", foo);
409: }
410:
411: /*
412: * plname is filled either by an option (-u Player or -uPlayer) or
413: * explicitly (-w implies wizard) or by askname.
414: * It may still contain a suffix denoting pl_character.
415: */
416: askname(){
417: register int c,ct;
418: printf("\nWho are you? ");
419: (void) fflush(stdout);
420: ct = 0;
421: while((c = getchar()) != '\n'){
422: if(c == EOF) error("End of input\n");
423: /* some people get confused when their erase char is not ^H */
424: if(c == '\010') {
425: if(ct) ct--;
426: continue;
427: }
428: if(c != '-')
429: if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_';
430: if(ct < sizeof(plname)-1) plname[ct++] = c;
431: }
432: plname[ct] = 0;
433: if(ct == 0) askname();
434: }
435:
436: /*VARARGS1*/
437: impossible(s,x1,x2)
438: register char *s;
439: {
440: pline(s,x1,x2);
441: pline("Program in disorder - perhaps you'd better Quit.");
442: }
443:
444: #ifdef CHDIR
445: static
446: chdirx(dir, wr)
447: char *dir;
448: boolean wr;
449: {
450:
451: #ifdef SECURE
452: if(dir /* User specified directory? */
453: #ifdef HACKDIR
454: && strcmp(dir, HACKDIR) /* and not the default? */
455: #endif HACKDIR
456: ) {
457: (void) setuid(getuid()); /* Ron Wessels */
458: (void) setgid(getgid());
459: }
460: #endif SECURE
461:
462: #ifdef HACKDIR
463: if(dir == NULL)
464: dir = HACKDIR;
465: #endif HACKDIR
466:
467: if(dir && chdir(dir) < 0) {
468: perror(dir);
469: error("Cannot chdir to %s.", dir);
470: }
471:
472: /* warn the player if he cannot write the record file */
473: /* perhaps we should also test whether . is writable */
474: /* unfortunately the access systemcall is worthless */
475: if(wr) {
476: register fd;
477:
478: if(dir == NULL)
479: dir = ".";
480: if((fd = open(RECORD, 2)) < 0) {
481: printf("Warning: cannot write %s/%s", dir, RECORD);
482: getret();
483: } else
484: (void) close(fd);
485: }
486: }
487: #endif CHDIR
488:
489: stop_occupation()
490: {
491: if(occupation) {
492: pline("You stop %s.", occtxt);
493: occupation = 0;
494: }
495: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.