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*/