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