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