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