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