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 STATIC_DCL void FDECL(interrupt_multi, (const char *,int,int));
17 
18 static int prev_hp_notify;
19 
20 char *
hpnotify_format_str(char * str)21 hpnotify_format_str(char *str)
22 {
23     static char buf[128];
24     char *f, *p, *end;
25     int ispercent = 0;
26 
27     buf[0] = '\0';
28 
29     if (!str) return NULL;
30 
31     f = str;
32     p = buf;
33     end = buf + sizeof(buf) - 10;
34 
35     while (*f) {
36       if (ispercent) {
37 	switch (*f) {
38 	case 'a':
39 	    snprintf (p, end + 1 - p, "%ld", (long)abs(uhp()-prev_hp_notify));
40 	  while (*p != '\0')
41 	    p++;
42 	  break;
43         case 'c':
44 	    snprintf (p, end + 1 - p, "%c", (prev_hp_notify > uhp() ? '-' : '+'));
45 	  p++;
46 	  break;
47 	case 'm':
48 	    snprintf (p, end + 1 - p, "%ld", (long)uhpmax());
49 	  while (*p != '\0')
50 	    p++;
51 	  break;
52 	case 'H':
53 	    if (uhp() == uhpmax()) {
54 	    snprintf (p, end + 1 - p, "%s", "max");
55 	  } else {
56 		snprintf (p, end + 1 - p, "%ld", (long)uhp());
57 	  }
58 	  while (*p != '\0')
59 	    p++;
60 	  break;
61 	case 'h':
62 	    snprintf (p, end + 1 - p, "%ld", (long)uhp());
63 	  while (*p != '\0')
64 	    p++;
65 	  break;
66 	default:
67 	  *p = *f;
68 	  if (p < end)
69 	    p++;
70 	}
71 	ispercent = 0;
72       } else {
73 	if (*f == '%')
74 	  ispercent = 1;
75 	else {
76 	  *p = *f;
77 	  if (p < end)
78 	    p++;
79 	}
80       }
81       f++;
82     }
83     *p = '\0';
84 
85     return buf;
86 }
87 
88 /* Elven players cannot regenerate if in direct contact with cold
89  * iron, and vampiric players cannot if in direct contact with silver.
90  * Make an exception for your quest artifact, though -- currently,
91  * the only worn iron quest artifacts are weapons, a helm, and an
92  * amulet, and the only worn silver quest artifact is a shield.
93  * It is also not possible to hold artifacts as secondary weapons.
94  */
95 boolean
can_regenerate()96 can_regenerate()
97 {
98     if (is_elf(youmonst.data)) {
99 	if (uwep && is_iron(uwep) &&
100 		!is_quest_artifact(uwep) && !uarmg) return 0;
101 #ifdef TOURIST
102 	if (uarm && is_iron(uarm) && !uarmu) return 0;
103 	if (uarmu && is_iron(uarmu)) return 0;
104 	if (uarmc && is_iron(uarmc) && !uarmu && !uarm) return 0;
105 #else
106 	if (uarm && is_iron(uarm)) return 0;
107 	if (uarmc && is_iron(uarmc) && !uarm) return 0;
108 #endif
109 	if (uarmh && is_iron(uarmh) &&
110 		!is_quest_artifact(uarmh)) return 0;
111 	if (uarms && is_iron(uarms) && !uarmg) return 0;
112 	if (uarmg && is_iron(uarmg)) return 0;
113 	if (uarmf && is_iron(uarmf)) return 0;
114 	if (uleft && is_iron(uleft)) return 0;
115 	if (uright && is_iron(uright)) return 0;
116 #ifdef TOURIST
117 	if (uamul && is_iron(uamul) &&
118 		!is_quest_artifact(uamul) && !uarmu && !uarm) return 0;
119 #else
120 	if (uamul && is_iron(uamul) &&
121 		!is_quest_artifact(uamul) && !uarm) return 0;
122 #endif
123 	if (ublindf && is_iron(ublindf)) return 0;
124 	if (uchain && is_iron(uchain)) return 0;
125 	if (uswapwep && is_iron(uswapwep) && u.twoweap) return 0;
126     } else if (is_vampiric(youmonst.data)) {
127 	if (uwep && is_silver(uwep) && !uarmg) return 0;
128 	if (uarms && is_silver(uarms) &&
129 		!is_quest_artifact(uarms) && !uarmg) return 0;
130 	if (uleft && is_silver(uleft)) return 0;
131 	if (uright && is_silver(uright)) return 0;
132     }
133     return 1;
134 }
135 
136 void
moveloop()137 moveloop()
138 {
139 #if defined(MICRO) || defined(WIN32)
140     char ch;
141     int abort_lev;
142 #endif
143     int moveamt = 0, wtcap = 0, change = 0;
144     boolean didmove = FALSE, monscanmove = FALSE;
145     /* don't make it obvious when monsters will start speeding up */
146     int monclock;
147     int timeout_start = rnd(10000)+25000;
148     int clock_base = 80000L-timeout_start;
149     int past_clock;
150     /* for keeping track of Elbereth and correctstatus line display */
151     int was_on_elbereth = 0;
152     int is_on_elbereth = 0;
153     boolean can_regen = can_regenerate();
154 
155     flags.moonphase = phase_of_the_moon();
156     if(flags.moonphase == FULL_MOON) {
157 	You("are lucky!  Full moon tonight.");
158 	change_luck(1);
159     } else if(flags.moonphase == NEW_MOON) {
160 	pline("Be careful!  New moon tonight.");
161     }
162     flags.friday13 = friday_13th();
163     if (flags.friday13) {
164 	pline("Watch out!  Bad things can happen on Friday the 13th.");
165 	change_luck(-1);
166     }
167 
168     initrack();
169 
170 
171     /* Note:  these initializers don't do anything except guarantee that
172 	    we're linked properly.
173     */
174     decl_init();
175     monst_init();
176     monstr_init();	/* monster strengths */
177     objects_init();
178     dragons_init();
179     doredraw(); /* partial workaround to http://sourceforge.net/apps/trac/unnethack/ticket/2 */
180     shop_selection_init();
181 
182 #ifdef WIZARD
183     if (wizard) add_debug_extended_commands();
184 #endif
185 
186     (void) encumber_msg(); /* in case they auto-picked up something */
187 
188     u.uz0.dlevel = u.uz.dlevel;
189     youmonst.movement = NORMAL_SPEED;	/* give the hero some movement points */
190     prev_hp_notify = uhp();
191 #ifdef WHEREIS_FILE
192     touch_whereis();
193 #endif
194 
195     for(;;) {
196 	get_nh_event();
197 #ifdef POSITIONBAR
198 	do_positionbar();
199 #endif
200 
201 	didmove = flags.move;
202 	if(didmove) {
203 	    /* actual time passed */
204 	    youmonst.movement -= NORMAL_SPEED;
205 
206 	    do { /* hero can't move this turn loop */
207 		wtcap = encumber_msg();
208 
209 		flags.mon_moving = TRUE;
210 		do {
211 		    monscanmove = movemon();
212 		    if (youmonst.movement > NORMAL_SPEED)
213 			break;	/* it's now your turn */
214 		} while (monscanmove);
215 		flags.mon_moving = FALSE;
216 		/* heaven or hell mode: player always has 1 maxhp */
217 		if (heaven_or_hell_mode)
218 		{
219 			u.uhpmax = 1;
220 			if (u.uhp > u.uhpmax)
221 				u.uhp = u.uhpmax;
222 		}
223 
224 		if (!monscanmove && youmonst.movement < NORMAL_SPEED) {
225 		    /* both you and the monsters are out of steam this round */
226 		    /* set up for a new turn */
227 		    struct monst *mtmp;
228 		    mcalcdistress();	/* adjust monsters' trap, blind, etc */
229 
230 		    /* reallocate movement rations to monsters */
231 		    for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
232 			mtmp->movement += mcalcmove(mtmp);
233 
234 			 /* Vanilla generates a critter every 70-ish turns.
235 			  * The rate accelerates to every 50 or so below the Castle,
236 			  * and 'round every 25 turns once you've done the Invocation.
237 			  *
238 			  * We will push it even further.  Monsters post-Invocation
239 			  * will almost always appear on the stairs (if present), and
240 			  * much more frequently; this, along with the extra intervene()
241 			  * calls, should certainly make it seem like you're wading back
242 			  * through the teeming hordes.
243 			  *
244 			  * Aside from that, a more general clock should be put on things;
245 			  * after about 30,000 turns, the frequency rate of appearance
246 			  * and (TODO) difficulty of monsters generated will slowly increase until
247 			  * it reaches the point it will be at as if you were post-Invocation.
248 			  *
249 			  * 80,000 turns should be adequate as a target mark for this effect;
250 			  * if you haven't ascended in 80,000 turns, you're intentionally
251 			  * fiddling around somewhere and will certainly be strong enough
252 			  * to handle anything that comes your way, so this won't be
253 			  * dropping newbies off the edge of the planet.  -- DSR 12/2/07
254 			  */
255 			monclock = 70;
256 			if (u.uevent.udemigod) {
257 				monclock = 10;
258 			} else {
259 				if (depth(&u.uz) > depth(&stronghold_level)) {
260 					monclock = 50;
261 				}
262 				past_clock = moves - timeout_start;
263 				if (past_clock > 0) {
264 					monclock -= past_clock*60/clock_base;
265 				}
266 			}
267 			/* make sure we don't fall off the bottom */
268 			if (monclock < 10) { monclock = 10; }
269 
270 			/* TODO: adj difficulty in makemon */
271 			if (!rn2(monclock)) {
272 				if (u.uevent.udemigod && xupstair && rn2(10)) {
273 					(void) makemon((struct permonst *)0, xupstair, yupstair, MM_ADJACENTOK);
274 				} else {
275 					(void) makemon((struct permonst *)0, 0, 0, NO_MM_FLAGS);
276 				}
277 			}
278 
279 		    /* calculate how much time passed. */
280 #ifdef STEED
281 		    if (u.usteed && u.umoved) {
282 			/* your speed doesn't augment steed's speed */
283 			moveamt = mcalcmove(u.usteed);
284 		    } else
285 #endif
286 		    {
287 			moveamt = youmonst.data->mmove;
288 
289 			if (Very_fast) {	/* speed boots or potion */
290 			    /* average movement is 1.67 times normal */
291 			    moveamt += NORMAL_SPEED / 2;
292 			    if (rn2(3) == 0) moveamt += NORMAL_SPEED / 2;
293 			} else if (Fast) {
294 			    /* average movement is 1.33 times normal */
295 			    if (rn2(3) != 0) moveamt += NORMAL_SPEED / 2;
296 			}
297 		    }
298 
299 		    switch (wtcap) {
300 			case UNENCUMBERED: break;
301 			case SLT_ENCUMBER: moveamt -= (moveamt / 4); break;
302 			case MOD_ENCUMBER: moveamt -= (moveamt / 2); break;
303 			case HVY_ENCUMBER: moveamt -= ((moveamt * 3) / 4); break;
304 			case EXT_ENCUMBER: moveamt -= ((moveamt * 7) / 8); break;
305 			default: break;
306 		    }
307 
308 		    youmonst.movement += moveamt;
309 		    if (youmonst.movement < 0) youmonst.movement = 0;
310 		    settrack();
311 
312 		    monstermoves++;
313 		    moves++;
314 
315 		    /********************************/
316 		    /* once-per-turn things go here */
317 		    /********************************/
318 
319 		    if (flags.bypasses) clear_bypasses();
320 		    if(Glib) glibr();
321 		    nh_timeout();
322 		    run_regions();
323 #ifdef DUNGEON_GROWTH
324 		    dgn_growths(TRUE, TRUE);
325 #endif
326 		    if (u.ublesscnt)  u.ublesscnt--;
327 		    if(flags.time && !flags.run)
328 			flags.botl = 1;
329 
330 		    /* One possible result of prayer is healing.  Whether or
331 		     * not you get healed depends on your current hit points.
332 		     * If you are allowed to regenerate during the prayer, the
333 		     * end-of-prayer calculation messes up on this.
334 		     * Another possible result is rehumanization, which requires
335 		     * that encumbrance and movement rate be recalculated.
336 		     */
337 		    if (u.uinvulnerable) {
338 			/* for the moment at least, you're in tiptop shape */
339 			wtcap = UNENCUMBERED;
340 		    } else if (Upolyd && youmonst.data->mlet == S_EEL && !is_pool(u.ux,u.uy) && !Is_waterlevel(&u.uz)) {
341 			if (u.mh > 1) {
342 			    u.mh--;
343 			    flags.botl = 1;
344 			} else if (u.mh < 1)
345 			    rehumanize();
346 		    } else if (Upolyd && u.mh < u.mhmax) {
347 			if (u.mh < 1)
348 			    rehumanize();
349 			else if (can_regenerate() && (Regeneration ||
350 				    (wtcap < MOD_ENCUMBER && !(moves%20)))) {
351 			    flags.botl = 1;
352 			    u.mh++;
353 			    interrupt_multi("Hit points", u.mh, u.mhmax);
354 			}
355 		    } else if (u.uhp < u.uhpmax && can_regenerate() &&
356 			 (wtcap < MOD_ENCUMBER || !u.umoved || Regeneration)) {
357 			if (u.ulevel > 9 && !(moves % 3)) {
358 			    int heal, Con = (int) ACURR(A_CON);
359 
360 			    if (Con <= 12) {
361 				heal = 1;
362 			    } else {
363 				heal = rnd(Con);
364 				if (heal > u.ulevel-9) heal = u.ulevel-9;
365 			    }
366 			    flags.botl = 1;
367 			    u.uhp += heal;
368 			    if(u.uhp > u.uhpmax)
369 				u.uhp = u.uhpmax;
370 			    interrupt_multi("Hit points", u.uhp, u.uhpmax);
371 			} else if (Regeneration ||
372 			     (u.ulevel <= 9 &&
373 			      !(moves % ((MAXULEV+12) / (u.ulevel+2) + 1)))) {
374 			    flags.botl = 1;
375 			    u.uhp++;
376 			    interrupt_multi("Hit points", u.uhp, u.uhpmax);
377 			}
378 		    }
379 
380 		    /* moving around while encumbered is hard work */
381 		    if (wtcap > MOD_ENCUMBER && u.umoved) {
382 			if(!(wtcap < EXT_ENCUMBER ? moves%30 : moves%10)) {
383 			    if (Upolyd && u.mh > 1) {
384 				u.mh--;
385 			    } else if (!Upolyd && u.uhp > 1) {
386 				u.uhp--;
387 			    } else {
388 				You("pass out from exertion!");
389 				exercise(A_CON, FALSE);
390 				fall_asleep(-10, FALSE);
391 			    }
392 			}
393 		    }
394 
395 		    if ((u.uen < u.uenmax) &&
396 			((wtcap < MOD_ENCUMBER &&
397 			  (!(moves%((MAXULEV + 8 - u.ulevel) *
398 				    (Role_if(PM_WIZARD) ? 3 : 4) / 6))))
399 			 || Energy_regeneration)) {
400 			u.uen += rn1((int)(ACURR(A_WIS) + ACURR(A_INT)) / 15 + 1,1);
401 			if (u.uen > u.uenmax)  u.uen = u.uenmax;
402 			flags.botl = 1;
403 			interrupt_multi("Magic energy", u.uen, u.uenmax);
404 		    }
405 
406 		    if(!u.uinvulnerable) {
407 			if(Teleportation && !rn2(85)) {
408 			    xchar old_ux = u.ux, old_uy = u.uy;
409 			    tele();
410 			    if (u.ux != old_ux || u.uy != old_uy) {
411 				if (!next_to_u()) {
412 				    check_leash(old_ux, old_uy);
413 				}
414 #ifdef REDO
415 				/* clear doagain keystrokes */
416 				pushch(0);
417 				savech(0);
418 #endif
419 			    }
420 			}
421 			/* delayed change may not be valid anymore */
422 			if ((change == 1 && !Polymorph) ||
423 			    (change == 2 && u.ulycn == NON_PM))
424 			    change = 0;
425 			if(Polymorph && !rn2(100))
426 			    change = 1;
427 			else if (u.ulycn >= LOW_PM && !Upolyd &&
428 				 !rn2(80 - (20 * night())))
429 			    change = 2;
430 			if (change && !Unchanging) {
431 			    if (multi >= 0) {
432 				if (occupation)
433 				    stop_occupation();
434 				else
435 				    nomul(0, 0);
436 				if (change == 1) polyself(FALSE);
437 				else you_were();
438 				change = 0;
439 			    }
440 			}
441 		    }
442 
443 		    if(Searching && multi >= 0) (void) dosearch0(1);
444 		    dosounds();
445 		    do_storms();
446 		    gethungry();
447 		    age_spells();
448 		    exerchk();
449 		    invault();
450 		    if (u.uhave.amulet) amulet();
451 		    if (!rn2(40+(int)(ACURR(A_DEX)*3)))
452 			u_wipe_engr(rnd(3));
453 		    if (u.uevent.udemigod && !u.uinvulnerable) {
454 			if (u.udg_cnt) u.udg_cnt--;
455 			if (!u.udg_cnt) {
456 			    intervene();
457 			    u.udg_cnt = rn1(200, (42+Luck));
458 			}
459 		    }
460 		    restore_attrib();
461 		    /* underwater and waterlevel vision are done here */
462 		    if (Is_waterlevel(&u.uz))
463 			movebubbles();
464 		    else if (Underwater)
465 			under_water(0);
466 		    /* vision while buried done here */
467 		    else if (u.uburied) under_ground(0);
468 
469 		    /* when immobile, count is in turns */
470 		    if(multi < 0) {
471 			if (++multi == 0) {	/* finished yet? */
472 			    unmul((char *)0);
473 			    /* if unmul caused a level change, take it now */
474 			    if (u.utotype) deferred_goto();
475 			}
476 		    }
477 		}
478 	    } while (youmonst.movement<NORMAL_SPEED); /* hero can't move loop */
479 
480 	    /******************************************/
481 	    /* once-per-hero-took-time things go here */
482 	    /******************************************/
483 
484 	    if (u.utrap && u.utraptype == TT_LAVA) {
485 		    if (!is_lava(u.ux,u.uy))
486 			    u.utrap = 0;
487 		    else if (!u.uinvulnerable) {
488 			    u.utrap -= 1<<8;
489 			    if (u.utrap < 1<<8) {
490 				    killer_format = KILLED_BY;
491 				    killer = "molten lava";
492 				    You("sink below the surface and die.");
493 				    done(DISSOLVED);
494 			    } else if (!u.umoved) {
495 				    Norep("You sink deeper into the lava.");
496 				    u.utrap += rnd(4);
497 			    }
498 		    }
499 	    }
500 
501 	} /* actual time passed */
502 
503 	/****************************************/
504 	/* once-per-player-input things go here */
505 	/****************************************/
506 
507 	find_ac();
508 	if(!flags.mv || Blind) {
509 	    /* redo monsters if hallu or wearing a helm of telepathy */
510 	    if (Hallucination) {	/* update screen randomly */
511 		see_monsters();
512 		see_objects();
513 		see_traps();
514 		if (u.uswallow) swallowed(0);
515 	    } else if (Unblind_telepat) {
516 		see_monsters();
517 	    } else if (Warning || Warn_of_mon)
518 	     	see_monsters();
519 
520 	    if (vision_full_recalc) vision_recalc(0);	/* vision! */
521 	}
522 
523 #ifdef ELBERETH
524 	/* check changes of Elbereth at current player location */
525 	is_on_elbereth = sengr_at("Elbereth", u.ux, u.uy);
526 	if (was_on_elbereth != is_on_elbereth) {
527 		was_on_elbereth = is_on_elbereth;
528 		flags.botlx = 1;
529 	}
530 #endif
531 
532 #ifdef REALTIME_ON_BOTL
533 	if (iflags.showrealtime) {
534 		/* Update the bottom line if the number of minutes has
535 		 * changed */
536 		time_t currenttime = get_realtime();
537 		if (currenttime / 60 != realtime_data.last_displayed_time / 60) {
538 			flags.botl = 1;
539 			realtime_data.last_displayed_time = currenttime;
540 		}
541 	}
542 #endif
543 
544 	if(flags.botl || flags.botlx) bot();
545 
546 	if (iflags.hp_notify && (prev_hp_notify != uhp())) {
547 	  pline("%s", hpnotify_format_str(iflags.hp_notify_fmt ? iflags.hp_notify_fmt : "[HP%c%a=%h]"));
548 	  prev_hp_notify = uhp();
549 	}
550 
551 	if (can_regen != can_regenerate()) {
552 	    if (!Hallucination){
553 		You_feel("%s.", (can_regen) ? "itchy" : "relief");
554 	    } else {
555 		You_feel("%s.", (can_regen) ? (is_elf(youmonst.data) ? "magnetic" :
556 			"tarnished") : "like you are no longer failing Organic Chemistry");
557 	    }
558 	    can_regen = can_regenerate();
559 	}
560 
561 	flags.move = 1;
562 
563 	if(multi >= 0 && occupation) {
564 #if defined(MICRO) || defined(WIN32)
565 	    abort_lev = 0;
566 	    if (kbhit()) {
567 		if ((ch = Getchar()) == ABORT)
568 		    abort_lev++;
569 # ifdef REDO
570 		else
571 		    pushch(ch);
572 # endif /* REDO */
573 	    }
574 	    if (!abort_lev && (*occupation)() == 0)
575 #else
576 	    if ((*occupation)() == 0)
577 #endif
578 		occupation = 0;
579 	    if(
580 #if defined(MICRO) || defined(WIN32)
581 		   abort_lev ||
582 #endif
583 		   monster_nearby()) {
584 		stop_occupation();
585 		reset_eat();
586 	    }
587 #if defined(MICRO) || defined(WIN32)
588 	    if (!(++occtime % 7))
589 		display_nhwindow(WIN_MAP, FALSE);
590 #endif
591 	    continue;
592 	}
593 
594 	if ((u.uhave.amulet || Clairvoyant) &&
595 	    !In_endgame(&u.uz) && !BClairvoyant &&
596 	    !(moves % 15) && !rn2(2))
597 		do_vicinity_map();
598 
599 #ifdef WIZARD
600 	if (iflags.sanity_check)
601 	    sanity_check();
602 #endif
603 
604 #ifdef CLIPPING
605 	/* just before rhack */
606 	cliparound(u.ux, u.uy);
607 #endif
608 
609 	u.umoved = FALSE;
610 
611 	if (multi > 0) {
612 	    lookaround();
613 	    if (!multi) {
614 		/* lookaround may clear multi */
615 		flags.move = 0;
616 		if (flags.time) flags.botl = 1;
617 		continue;
618 	    }
619 	    if (flags.mv) {
620 		if(multi < COLNO && !--multi)
621 		    flags.travel = iflags.travel1 = flags.mv = flags.run = 0;
622 		domove();
623 	    } else {
624 		--multi;
625 		rhack(save_cm);
626 	    }
627 	} else if (multi == 0) {
628 #ifdef MAIL
629 	    ckmailstatus();
630 	    maybe_hint();
631 #endif
632             maybe_tutorial();
633 	    rhack((char *)0);
634 	}
635 	if (u.utotype)		/* change dungeon level */
636 	    deferred_goto();	/* after rhack() */
637 	/* !flags.move here: multiple movement command stopped */
638 	else if (flags.time && (!flags.move || !flags.mv))
639 	    flags.botl = 1;
640 
641 	if (vision_full_recalc) vision_recalc(0);	/* vision! */
642 	/* when running in non-tport mode, this gets done through domove() */
643 	if ((!flags.run || iflags.runmode == RUN_TPORT) &&
644 		(multi && (!flags.travel ? !(multi % 7) : !(moves % 7L)))) {
645 	    if (flags.time && flags.run) flags.botl = 1;
646 	    display_nhwindow(WIN_MAP, FALSE);
647 	}
648     }
649 }
650 
651 void
stop_occupation()652 stop_occupation()
653 {
654 	if(occupation) {
655 		if (!maybe_finished_meal(TRUE))
656 		    You("stop %s.", occtxt);
657 		occupation = 0;
658 		flags.botl = 1; /* in case u.uhs changed */
659 /* fainting stops your occupation, there's no reason to sync.
660 		sync_hunger();
661 */
662 #ifdef REDO
663 		nomul(0, 0);
664 		pushch(0);
665 #endif
666 	}
667 }
668 
669 void
display_gamewindows()670 display_gamewindows()
671 {
672     WIN_MESSAGE = create_nhwindow(NHW_MESSAGE);
673     WIN_STATUS = create_nhwindow(NHW_STATUS);
674     WIN_MAP = create_nhwindow(NHW_MAP);
675     WIN_INVEN = create_nhwindow(NHW_MENU);
676 
677 #ifdef MAC
678     /*
679      * This _is_ the right place for this - maybe we will
680      * have to split display_gamewindows into create_gamewindows
681      * and show_gamewindows to get rid of this ifdef...
682      */
683 	if ( ! strcmp ( windowprocs . name , "mac" ) ) {
684 	    SanePositions ( ) ;
685 	}
686 #endif
687 
688     /*
689      * The mac port is not DEPENDENT on the order of these
690      * displays, but it looks a lot better this way...
691      */
692     display_nhwindow(WIN_STATUS, FALSE);
693     display_nhwindow(WIN_MESSAGE, FALSE);
694     clear_glyph_buffer();
695     display_nhwindow(WIN_MAP, FALSE);
696 }
697 
698 void
newgame()699 newgame()
700 {
701 	int i;
702 
703 #ifdef MFLOPPY
704 	gameDiskPrompt();
705 #endif
706 
707 	flags.ident = 1;
708 
709 	for (i = 0; i < NUMMONS; i++)
710 		mvitals[i].mvflags = mons[i].geno & G_NOCORPSE;
711 
712 	init_objects();		/* must be before u_init() */
713 
714 	flags.pantheon = -1;	/* role_init() will reset this */
715 	role_init();		/* must be before init_dungeons(), u_init(),
716 				 * and init_artifacts() */
717 
718 	init_dungeons();	/* must be before u_init() to avoid rndmonst()
719 				 * creating odd monsters for any tins and eggs
720 				 * in hero's initial inventory */
721 	init_artifacts();	/* before u_init() in case $WIZKIT specifies
722 				 * any artifacts */
723 	u_init();
724 
725 #ifndef NO_SIGNAL
726 	(void) signal(SIGINT, (SIG_RET_TYPE) done1);
727 #endif
728 #ifdef NEWS
729 	if(iflags.news) display_file_area(NEWS_AREA, NEWS, FALSE);
730 #endif
731 	load_qtlist();	/* load up the quest text info */
732 /*	quest_init();*/	/* Now part of role_init() */
733 
734 	mklev();
735 	u_on_upstairs();
736 	vision_reset();		/* set up internals for level (after mklev) */
737 	check_special_room(FALSE);
738 
739 	flags.botlx = 1;
740 
741 	/* Move the monster from under you or else
742 	 * makedog() will fail when it calls makemon().
743 	 *			- ucsfcgl!kneller
744 	 */
745 	if(MON_AT(u.ux, u.uy)) mnexto(m_at(u.ux, u.uy));
746 	(void) makedog();
747 	docrt();
748 #ifdef CONVICT
749 	if (Role_if(PM_CONVICT)) {
750 		setworn(mkobj(CHAIN_CLASS, TRUE), W_CHAIN);
751 		setworn(mkobj(BALL_CLASS, TRUE), W_BALL);
752 		uball->spe = 1;
753 		placebc();
754 		newsym(u.ux,u.uy);
755 	}
756 #endif /* CONVICT */
757 
758 	if (flags.legacy) {
759 		flush_screen(1);
760 #ifdef CONVICT
761 	if (Role_if(PM_CONVICT)) {
762 		com_pager(199);
763 	} else {
764 		com_pager(1);
765 	}
766 #else
767 		com_pager(1);
768 #endif /* CONVICT */
769 	}
770 
771 #ifdef INSURANCE
772 	save_currentstate();
773 #endif
774 	program_state.something_worth_saving++;	/* useful data now exists */
775 
776 #if defined(RECORD_REALTIME) || defined(REALTIME_ON_BOTL)
777 
778 	/* Start the timer here */
779 	realtime_data.realtime = (time_t)0L;
780 
781 #if defined(BSD) && !defined(POSIX_TYPES)
782 	(void) time((long *)&realtime_data.restoretime);
783 #else
784 	(void) time(&realtime_data.restoretime);
785 #endif
786 
787 #endif /* RECORD_REALTIME || REALTIME_ON_BOTL */
788 
789 	/* Success! */
790 	welcome(TRUE);
791 	return;
792 }
793 
794 /* show "welcome [back] to unnethack" message at program startup */
795 void
welcome(new_game)796 welcome(new_game)
797 boolean new_game;	/* false => restoring an old game */
798 {
799     char buf[BUFSZ];
800     boolean currentgend = Upolyd ? u.mfemale : flags.female;
801     const char *role_name;
802     char *annotation;
803 
804     /*
805      * The "welcome back" message always describes your innate form
806      * even when polymorphed or wearing a helm of opposite alignment.
807      * Alignment is shown unconditionally for new games; for restores
808      * it's only shown if it has changed from its original value.
809      * Sex is shown for new games except when it is redundant; for
810      * restores it's only shown if different from its original value.
811      */
812     *buf = '\0';
813     if (new_game || u.ualignbase[A_ORIGINAL] != u.ualignbase[A_CURRENT])
814 	Sprintf(eos(buf), " %s", align_str(u.ualignbase[A_ORIGINAL]));
815     if (!urole.name.f &&
816 	    (new_game ? (urole.allow & ROLE_GENDMASK) == (ROLE_MALE|ROLE_FEMALE) :
817 	     currentgend != flags.initgend))
818 	Sprintf(eos(buf), " %s", genders[currentgend].adj);
819 
820     role_name = (currentgend && urole.name.f) ? urole.name.f : urole.name.m;
821     pline(new_game ? "%s %s, welcome to UnNetHack!  You are a%s %s %s."
822 		   : "%s %s, the%s %s %s, welcome back to UnNetHack!",
823 	  Hello((struct monst *) 0), plname, buf, urace.adj, role_name);
824 #ifdef LIVELOGFILE
825     /* Start live reporting */
826 	  livelog_start();
827 	  livelog_game_started(new_game ? "started" : "resumed",
828 	                       buf, urace.adj, role_name);
829 #endif
830 	/* show level annotation when restoring the level */
831 	if (!new_game && iflags.show_annotation &&
832 	    (annotation = get_annotation(&u.uz))) {
833 		You("annotated this level: %s", annotation);
834 	}
835 }
836 
837 #ifdef POSITIONBAR
838 STATIC_DCL void
do_positionbar()839 do_positionbar()
840 {
841 	static char pbar[COLNO];
842 	char *p;
843 
844 	p = pbar;
845 	/* up stairway */
846 	if (upstair.sx &&
847 	   (glyph_to_cmap(level.locations[upstair.sx][upstair.sy].glyph) ==
848 	    S_upstair ||
849  	    glyph_to_cmap(level.locations[upstair.sx][upstair.sy].glyph) ==
850 	    S_upladder)) {
851 		*p++ = '<';
852 		*p++ = upstair.sx;
853 	}
854 	if (sstairs.sx &&
855 	   (glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) ==
856 	    S_upstair ||
857  	    glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) ==
858 	    S_upladder)) {
859 		*p++ = '<';
860 		*p++ = sstairs.sx;
861 	}
862 
863 	/* down stairway */
864 	if (dnstair.sx &&
865 	   (glyph_to_cmap(level.locations[dnstair.sx][dnstair.sy].glyph) ==
866 	    S_dnstair ||
867  	    glyph_to_cmap(level.locations[dnstair.sx][dnstair.sy].glyph) ==
868 	    S_dnladder)) {
869 		*p++ = '>';
870 		*p++ = dnstair.sx;
871 	}
872 	if (sstairs.sx &&
873 	   (glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) ==
874 	    S_dnstair ||
875  	    glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) ==
876 	    S_dnladder)) {
877 		*p++ = '>';
878 		*p++ = sstairs.sx;
879 	}
880 
881 	/* hero location */
882 	if (u.ux) {
883 		*p++ = '@';
884 		*p++ = u.ux;
885 	}
886 	/* fence post */
887 	*p = 0;
888 
889 	update_positionbar(pbar);
890 }
891 #endif
892 
893 #if defined(REALTIME_ON_BOTL) || defined (RECORD_REALTIME)
894 time_t
get_realtime(void)895 get_realtime(void)
896 {
897 	time_t current_time = 0;
898 	/* Add maximally this many seconds per invocation to get somewhat
899 	 * reasonable realtime values. */
900 #define MAX_IDLE_TIME_IN_SECONDS 60
901 	static time_t time_last_activity = 0;
902 	static time_t time_spent_playing = 0;
903 
904     /* Get current time */
905 #if defined(BSD) && !defined(POSIX_TYPES)
906 	(void) time((long *)&current_time);
907 #else
908 	(void) time(&current_time);
909 #endif
910 
911 	/* Initialize last_activity_time. */
912 	if (time_last_activity == 0) {
913 		time_last_activity = current_time;
914 	}
915 
916 	/* Since the timer isn't set until the game starts, this prevents us
917 	 * from displaying nonsense on the bottom line before it does. */
918 	if (realtime_data.restoretime == 0) {
919 		time_spent_playing = realtime_data.realtime;
920 	} else {
921 		time_t idletime = current_time - time_last_activity;
922 		time_last_activity = current_time;
923 		/* Add time the player spent "thinking". */
924 		time_spent_playing += (idletime > MAX_IDLE_TIME_IN_SECONDS) ? MAX_IDLE_TIME_IN_SECONDS : idletime;
925 		/* Update realtime for livelog events. */
926 		realtime_data.realtime = time_spent_playing;
927 	}
928 
929 	return time_spent_playing;
930 }
931 #undef MAX_IDLE_TIME_IN_SECONDS
932 #endif /* REALTIME_ON_BOTL || RECORD_REALTIME */
933 
934 /** Interrupt a multiturn action if current_points is equal to max_points. */
935 STATIC_DCL
936 void
interrupt_multi(points,current_points,max_points)937 interrupt_multi(points, current_points, max_points)
938 const char *points;
939 int current_points;
940 int max_points;
941 {
942 	if (multi > 0 &&
943 	    current_points == max_points) {
944 		nomul(0, 0);
945 		if (flags.verbose) pline("%s restored.", points);
946 	}
947 }
948 
949 /*allmain.c*/
950