1 | /* SCCS Id: @(#)allmain.c 3.3 2000/05/05 */ 2 | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3 | /* NetHack may be freely redistributed. See license for details. */ 4 | 5 | /* various code that was replicated in *main.c */ 6 | 7 | #include "hack.h" 8 | 9 | #ifndef NO_SIGNAL 10 | #include <signal.h> 11 | #endif 12 | 13 | #ifdef POSITIONBAR 14 | STATIC_DCL void NDECL(do_positionbar); 15 | #endif 16 | 17 | #ifdef OVL0 18 | 19 | void 20 | moveloop() 21 | { 22 | #ifdef MICRO 23 | char ch; 24 | int abort_lev; 25 | #endif 26 | int moveamt = 0, wtcap = 0, change = 0; 27 | boolean didmove = FALSE, monscanmove = FALSE; 28 | 29 | flags.moonphase = phase_of_the_moon(); 30 | if(flags.moonphase == FULL_MOON) { 31 | You("are lucky! Full moon tonight."); 32 | change_luck(1); 33 | } else if(flags.moonphase == NEW_MOON) { 34 | pline("Be careful! New moon tonight."); 35 | } 36 | flags.friday13 = friday_13th(); 37 | if (flags.friday13) { 38 | pline("Watch out! Bad things can happen on Friday the 13th."); 39 | change_luck(-1); 40 | } 41 | 42 | initrack(); 43 | 44 | 45 | /* Note: these initializers don't do anything except guarantee that 46 | we're linked properly. 47 | */ 48 | decl_init(); 49 | monst_init(); 50 | monstr_init(); /* monster strengths */ 51 | objects_init(); 52 | 53 | #ifdef WIZARD 54 | if (wizard) add_debug_extended_commands(); 55 | #endif 56 | 57 | (void) encumber_msg(); /* in case they auto-picked up something */ 58 | 59 | u.uz0.dlevel = u.uz.dlevel; 60 | youmonst.movement = NORMAL_SPEED; /* give the hero some movement points */ 61 | 62 | for(;;) { 63 | #ifdef CLIPPING 64 | cliparound(u.ux, u.uy); 65 | #endif 66 | get_nh_event(); 67 | #ifdef POSITIONBAR 68 | do_positionbar(); 69 | #endif 70 | 71 | didmove = flags.move; 72 | if(didmove) { 73 | /* actual time passed */ 74 | youmonst.movement -= NORMAL_SPEED; 75 | 76 | do { /* hero can't move this turn loop */ 77 | wtcap = encumber_msg(); 78 | 79 | flags.mon_moving = TRUE; 80 | do { 81 | monscanmove = movemon(); 82 | if (youmonst.movement > NORMAL_SPEED) 83 | break; /* it's now your turn */ 84 | } while (monscanmove); 85 | flags.mon_moving = FALSE; 86 | 87 | if (!monscanmove && youmonst.movement < NORMAL_SPEED) { 88 | /* both you and the monsters are out of steam this round */ 89 | /* set up for a new turn */ 90 | struct monst *mtmp; 91 | mcalcdistress(); /* adjust monsters' trap, blind, etc */ 92 | 93 | /* reallocate movement rations to monsters */ 94 | for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) 95 | mtmp->movement += mcalcmove(mtmp); 96 | 97 | if(!rn2(u.uevent.udemigod ? 25 : 98 | (depth(&u.uz) > depth(&stronghold_level)) ? 50 : 70)) 99 | (void) makemon((struct permonst *)0, 0, 0, NO_MM_FLAGS); 100 | 101 | /* calculate how much time passed. */ 102 | #ifdef STEED 103 | if (u.usteed && flags.mv) { 104 | /* your speed doesn't augment steed's speed */ 105 | moveamt = mcalcmove(u.usteed); 106 | } else 107 | #endif 108 | { 109 | moveamt = youmonst.data->mmove; 110 | 111 | if (Very_fast) { /* speed boots or potion */ 112 | /* average movement is 1.67 times normal */ 113 | moveamt += NORMAL_SPEED / 2; 114 | if (rn2(3) == 0) moveamt += NORMAL_SPEED / 2; 115 | } else if (Fast) { 116 | /* average movement is 1.33 times normal */ 117 | if (rn2(3) != 0) moveamt += NORMAL_SPEED / 2; 118 | } 119 | } 120 | 121 | switch (wtcap) { 122 | case UNENCUMBERED: break; 123 | case SLT_ENCUMBER: moveamt -= (moveamt / 4); break; 124 | case MOD_ENCUMBER: moveamt -= (moveamt / 2); break; 125 | case HVY_ENCUMBER: moveamt -= ((moveamt * 3) / 4); break; 126 | case EXT_ENCUMBER: moveamt -= ((moveamt * 7) / 8); break; 127 | default: break; 128 | } 129 | 130 | youmonst.movement += moveamt; 131 | if (youmonst.movement < 0) youmonst.movement = 0; 132 | settrack(); 133 | 134 | monstermoves++; 135 | moves++; 136 | 137 | /********************************/ 138 | /* once-per-turn things go here */ 139 | /********************************/ 140 | 141 | if(Glib) glibr(); 142 | nh_timeout(); 143 | run_regions(); 144 | 145 | if (u.ublesscnt) u.ublesscnt--; 146 | if(flags.time && !flags.run) 147 | flags.botl = 1; 148 | 149 | /* One possible result of prayer is healing. Whether or 150 | * not you get healed depends on your current hit points. 151 | * If you are allowed to regenerate during the prayer, the 152 | * end-of-prayer calculation messes up on this. 153 | * Another possible result is rehumanization, which requires 154 | * that encumbrance and movement rate be recalculated. 155 | */ 156 | if (u.uinvulnerable) { 157 | /* for the moment at least, you're in tiptop shape */ 158 | wtcap = UNENCUMBERED; 159 | } else if (Upolyd && u.mh < u.mhmax) { 160 | if (u.mh < 1) 161 | rehumanize(); 162 | else if (Regeneration || 163 | (wtcap < MOD_ENCUMBER && !(moves%20))) { 164 | flags.botl = 1; 165 | u.mh++; 166 | } 167 | } else if (u.uhp < u.uhpmax && 168 | (wtcap < MOD_ENCUMBER || !flags.mv || Regeneration)) { 169 | if (u.ulevel > 9 && !(moves % 3)) { 170 | int heal, Con = (int) ACURR(A_CON); 171 | 172 | if (Con <= 12) { 173 | heal = 1; 174 | } else { 175 | heal = rnd(Con); 176 | if (heal > u.ulevel-9) heal = u.ulevel-9; 177 | } 178 | flags.botl = 1; 179 | u.uhp += heal; 180 | if(u.uhp > u.uhpmax) 181 | u.uhp = u.uhpmax; 182 | } else if (Regeneration || 183 | (u.ulevel <= 9 && 184 | !(moves % ((MAXULEV+12) / (u.ulevel+2) + 1)))) { 185 | flags.botl = 1; 186 | u.uhp++; 187 | } 188 | } 189 | 190 | if (wtcap > MOD_ENCUMBER && flags.mv) { 191 | if(!(wtcap < EXT_ENCUMBER ? moves%30 : moves%10)) { 192 | if (Upolyd && u.mh > 1) { 193 | u.mh--; 194 | } else if (!Upolyd && u.uhp > 1) { 195 | u.uhp--; 196 | } else { 197 | You("pass out from exertion!"); 198 | exercise(A_CON, FALSE); 199 | fall_asleep(-10, FALSE); 200 | } 201 | } 202 | } 203 | 204 | if ((u.uen < u.uenmax) && 205 | ((wtcap < MOD_ENCUMBER && 206 | (!(moves%((MAXULEV + 8 - u.ulevel) * 207 | (Role_if(PM_WIZARD) ? 3 : 4) / 6)))) 208 | || Energy_regeneration)) { 209 | u.uen += rn1((int)(ACURR(A_WIS) + ACURR(A_INT)) / 15 + 1,1); 210 | if (u.uen > u.uenmax) u.uen = u.uenmax; 211 | flags.botl = 1; 212 | } 213 | 214 | if(!u.uinvulnerable) { 215 | if(Teleportation && !rn2(85)) { 216 | #ifdef REDO 217 | xchar old_ux = u.ux, old_uy = u.uy; 218 | #endif 219 | tele(); 220 | #ifdef REDO 221 | if (u.ux != old_ux || u.uy != old_uy) { 222 | /* clear doagain keystrokes */ 223 | pushch(0); 224 | savech(0); 225 | } 226 | #endif 227 | } 228 | if(Polymorph && !rn2(100)) 229 | change = 1; 230 | else if (u.ulycn >= LOW_PM && !rn2(80 - (20 * night()))) 231 | change = 2; 232 | if (change && !Unchanging) { 233 | if (multi >= 0) { 234 | if (occupation) 235 | stop_occupation(); 236 | else 237 | nomul(0); 238 | if (change == 1) polyself(); 239 | else you_were(); 240 | change = 0; 241 | } 242 | } 243 | } 244 | 245 | if(Searching && multi >= 0) (void) dosearch0(1); 246 | dosounds(); 247 | do_storms(); 248 | gethungry(); 249 | age_spells(); 250 | exerchk(); 251 | invault(); 252 | if (u.uhave.amulet) amulet(); 253 | if (!rn2(40+(int)(ACURR(A_DEX)*3))) 254 | u_wipe_engr(rnd(3)); 255 | if (u.uevent.udemigod && !u.uinvulnerable) { 256 | if (u.udg_cnt) u.udg_cnt--; 257 | if (!u.udg_cnt) { 258 | intervene(); 259 | u.udg_cnt = rn1(200, 50); 260 | } 261 | } 262 | restore_attrib(); 263 | /* underwater and waterlevel vision are done here */ 264 | if (Is_waterlevel(&u.uz)) 265 | movebubbles(); 266 | else if (Underwater) 267 | under_water(0); 268 | /* vision while buried done here */ 269 | else if (u.uburied) under_ground(0); 270 | 271 | /* when immobile, count is in turns */ 272 | if(multi < 0) { 273 | if (++multi == 0) /* finished yet? */ 274 | unmul((char *)0); 275 | } 276 | } 277 | } while (youmonst.movement<NORMAL_SPEED); /* hero can't move loop */ 278 | 279 | /******************************************/ 280 | /* once-per-hero-took-time things go here */ 281 | /******************************************/ 282 | 283 | 284 | } /* actual time passed */ 285 | 286 | /****************************************/ 287 | /* once-per-player-input things go here */ 288 | /****************************************/ 289 | 290 | find_ac(); 291 | if(!flags.mv || Blind) { 292 | /* redo monsters if hallu or wearing a helm of telepathy */ 293 | if (Hallucination) { /* update screen randomly */ 294 | see_monsters(); 295 | see_objects(); 296 | see_traps(); 297 | if (u.uswallow) swallowed(0); 298 | } else if (Unblind_telepat) { 299 | see_monsters(); 300 | } else if (Warning || Warn_of_mon) 301 | see_monsters(); 302 | 303 | if (vision_full_recalc) vision_recalc(0); /* vision! */ 304 | } 305 | if(flags.botl || flags.botlx) bot(); 306 | 307 | flags.move = 1; 308 | 309 | if(multi >= 0 && occupation) { 310 | #ifdef MICRO 311 | abort_lev = 0; 312 | if (kbhit()) { 313 | if ((ch = Getchar()) == ABORT) 314 | abort_lev++; 315 | # ifdef REDO 316 | else 317 | pushch(ch); 318 | # endif /* REDO */ 319 | } 320 | if (!abort_lev && (*occupation)() == 0) 321 | #else 322 | if ((*occupation)() == 0) 323 | #endif 324 | occupation = 0; 325 | if( 326 | #ifdef MICRO 327 | abort_lev || 328 | #endif 329 | monster_nearby()) { 330 | stop_occupation(); 331 | reset_eat(); 332 | } 333 | #ifdef MICRO 334 | if (!(++occtime % 7)) 335 | display_nhwindow(WIN_MAP, FALSE); 336 | #endif 337 | continue; 338 | } 339 | 340 | if ((u.uhave.amulet || Clairvoyant) && 341 | !In_endgame(&u.uz) && !BClairvoyant && 342 | !(moves % 15) && !rn2(2)) 343 | do_vicinity_map(); 344 | 345 | if(u.utrap && u.utraptype == TT_LAVA) { 346 | if(!is_lava(u.ux,u.uy)) 347 | u.utrap = 0; 348 | else if (!u.uinvulnerable) { 349 | u.utrap -= 1<<8; 350 | if(u.utrap < 1<<8) { 351 | killer_format = KILLED_BY; 352 | killer = "molten lava"; 353 | You("sink below the surface and die."); 354 | done(DISSOLVED); 355 | } else if(didmove && !u.umoved) { 356 | Norep("You sink deeper into the lava."); 357 | u.utrap += rnd(4); 358 | } 359 | } 360 | } 361 | 362 | #ifdef WIZARD 363 | if (iflags.sanity_check) 364 | sanity_check(); 365 | #endif 366 | 367 | u.umoved = FALSE; 368 | 369 | if (multi > 0) { 370 | lookaround(); 371 | if (!multi) { 372 | /* lookaround may clear multi */ 373 | flags.move = 0; 374 | continue; 375 | } 376 | if (flags.mv) { 377 | if(multi < COLNO && !--multi) 378 | flags.mv = flags.run = 0; 379 | domove(); 380 | } else { 381 | --multi; 382 | rhack(save_cm); 383 | } 384 | } else if (multi == 0) { 385 | #ifdef MAIL 386 | ckmailstatus(); 387 | #endif 388 | rhack((char *)0); 389 | } 390 | if (u.utotype) /* change dungeon level */ 391 | deferred_goto(); /* after rhack() */ 392 | /* !flags.move here: multiple movement command stopped */ 393 | else if (flags.time && (!flags.move || !flags.mv)) 394 | flags.botl = 1; 395 | 396 | if (vision_full_recalc) vision_recalc(0); /* vision! */ 397 | if (multi && multi%7 == 0) 398 | display_nhwindow(WIN_MAP, FALSE); 399 | } 400 | } 401 | 402 | #endif /* OVL0 */ 403 | #ifdef OVL1 404 | 405 | void 406 | stop_occupation() 407 | { 408 | if(occupation) { 409 | You("stop %s.", occtxt); 410 | occupation = 0; 411 | /* fainting stops your occupation, there's no reason to sync. 412 | sync_hunger(); 413 | */ 414 | #ifdef REDO 415 | nomul(0); 416 | pushch(0); 417 | #endif 418 | } 419 | } 420 | 421 | #endif /* OVL1 */ 422 | #ifdef OVLB 423 | 424 | void 425 | display_gamewindows() 426 | { 427 | WIN_MESSAGE = create_nhwindow(NHW_MESSAGE); 428 | WIN_STATUS = create_nhwindow(NHW_STATUS); 429 | WIN_MAP = create_nhwindow(NHW_MAP); 430 | WIN_INVEN = create_nhwindow(NHW_MENU); 431 | 432 | #ifdef MAC 433 | /* 434 | * This _is_ the right place for this - maybe we will 435 | * have to split display_gamewindows into create_gamewindows 436 | * and show_gamewindows to get rid of this ifdef... 437 | */ 438 | if ( ! strcmp ( windowprocs . name , "mac" ) ) { 439 | SanePositions ( ) ; 440 | } 441 | #endif 442 | 443 | /* 444 | * The mac port is not DEPENDENT on the order of these 445 | * displays, but it looks a lot better this way... 446 | */ 447 | display_nhwindow(WIN_STATUS, FALSE); 448 | display_nhwindow(WIN_MESSAGE, FALSE); 449 | clear_glyph_buffer(); 450 | display_nhwindow(WIN_MAP, FALSE); 451 | } 452 | 453 | void 454 | newgame() 455 | { 456 | int i; 457 | 458 | #ifdef MFLOPPY 459 | gameDiskPrompt(); 460 | #endif 461 | 462 | flags.ident = 1; 463 | 464 | for (i = 0; i < NUMMONS; i++) 465 | mvitals[i].mvflags = mons[i].geno & G_NOCORPSE; 466 | 467 | init_objects(); /* must be before u_init() */ 468 | 469 | flags.pantheon = -1; /* role_init() will reset this */ 470 | role_init(); /* must be before init_dungeons(), u_init(), 471 | * and init_artifacts() */ 472 | 473 | init_dungeons(); /* must be before u_init() to avoid rndmonst() 474 | * creating odd monsters for initial tins and 475 | * eggs */ 476 | u_init(); 477 | init_artifacts(); 478 | 479 | #ifndef NO_SIGNAL 480 | (void) signal(SIGINT, (SIG_RET_TYPE) done1); 481 | #endif 482 | #ifdef NEWS 483 | if(iflags.news) display_file(NEWS, FALSE); 484 | #endif 485 | load_qtlist(); /* load up the quest text info */ 486 | /* quest_init();*/ /* Now part of role_init() */ 487 | 488 | mklev(); 489 | u_on_upstairs(); 490 | vision_reset(); /* set up internals for level (after mklev) */ 491 | check_special_room(FALSE); 492 | 493 | flags.botlx = 1; 494 | 495 | /* Move the monster from under you or else 496 | * makedog() will fail when it calls makemon(). 497 | * - ucsfcgl!kneller 498 | */ 499 | if(MON_AT(u.ux, u.uy)) mnexto(m_at(u.ux, u.uy)); 500 | (void) makedog(); 501 | docrt(); 502 | 503 | if (flags.legacy) { 504 | flush_screen(1); 505 | com_pager(1); 506 | } 507 | 508 | #ifdef INSURANCE 509 | save_currentstate(); 510 | #endif 511 | program_state.something_worth_saving++; /* useful data now exists */ 512 | 513 | /* Success! */ 514 | welcome(TRUE); 515 | return; 516 | } 517 | 518 | /* show "welcome [back] to nethack" message at program startup */ 519 | void 520 | welcome(new_game) 521 | boolean new_game; /* false => restoring an old game */ 522 | { 523 | char buf[BUFSZ]; 524 | boolean currentgend = Upolyd ? u.mfemale : flags.female; 525 | 526 | /* 527 | * The "welcome back" message always describes your innate form 528 | * even when polymorphed or wearing a helm of opposite alignment. 529 | * Alignment is shown unconditionally for new games; for restores 530 | * it's only shown if it has changed from its original value. 531 | * Sex is shown for new games except when it is redundant; for 532 | * restores it's only shown if different from its original value. 533 | */ 534 | *buf = '\0'; 535 | if (new_game || u.ualignbase[A_ORIGINAL] != u.ualignbase[A_CURRENT]) 536 | Sprintf(eos(buf), " %s", align_str(u.ualignbase[A_ORIGINAL])); 537 | if (!urole.name.f && 538 | (new_game ? (urole.allow & ROLE_GENDMASK) == (ROLE_MALE|ROLE_FEMALE) : 539 | currentgend != flags.initgend)) 540 | Sprintf(eos(buf), " %s", genders[currentgend].adj); 541 | 542 | pline(new_game ? "%s %s, welcome to NetHack! You are a%s %s %s." 543 | : "%s %s, the%s %s %s, welcome back to NetHack!", 544 | Hello((struct monst *) 0), plname, buf, urace.adj, 545 | (currentgend && urole.name.f) ? urole.name.f : urole.name.m); 546 | } 547 | 548 | #ifdef POSITIONBAR 549 | STATIC_DCL void 550 | do_positionbar() 551 | { 552 | static char pbar[COLNO]; 553 | char *p; 554 | 555 | p = pbar; 556 | /* up stairway */ 557 | if (upstair.sx && 558 | (glyph_to_cmap(level.locations[upstair.sx][upstair.sy].glyph) == 559 | S_upstair || 560 | glyph_to_cmap(level.locations[upstair.sx][upstair.sy].glyph) == 561 | S_upladder)) { 562 | *p++ = '<'; 563 | *p++ = upstair.sx; 564 | } 565 | if (sstairs.sx && 566 | (glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) == 567 | S_upstair || 568 | glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) == 569 | S_upladder)) { 570 | *p++ = '<'; 571 | *p++ = sstairs.sx; 572 | } 573 | 574 | /* down stairway */ 575 | if (dnstair.sx && 576 | (glyph_to_cmap(level.locations[dnstair.sx][dnstair.sy].glyph) == 577 | S_dnstair || 578 | glyph_to_cmap(level.locations[dnstair.sx][dnstair.sy].glyph) == 579 | S_dnladder)) { 580 | *p++ = '>'; 581 | *p++ = dnstair.sx; 582 | } 583 | if (sstairs.sx && 584 | (glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) == 585 | S_dnstair || 586 | glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) == 587 | S_dnladder)) { 588 | *p++ = '>'; 589 | *p++ = sstairs.sx; 590 | } 591 | 592 | /* hero location */ 593 | if (u.ux) { 594 | *p++ = '@'; 595 | *p++ = u.ux; 596 | } 597 | /* fence post */ 598 | *p = 0; 599 | 600 | update_positionbar(pbar); 601 | } 602 | #endif 603 | 604 | #endif /* OVLB */ 605 | 606 | /*allmain.c*/