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