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
14STATIC_DCL void NDECL(do_positionbar);
15#endif
16
17#ifdef OVL0
18
19void
20moveloop()
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
429void
430stop_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
450void
451display_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
479void
480newgame()
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 */
546void
547welcome(new_game)
548boolean 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
576STATIC_DCL void
577do_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