NHDT->ANH, nethack->anethack, nhdat->anhdat
[aNetHack.git] / src / allmain.c
blob2f3f94b5d82ca2d2b6f117b04038429b6bd97db5
1 /* aNetHack 0.0.1 allmain.c $ANH-Date: 1463217182 2016/05/14 09:13:02 $ $ANH-Branch: master $:$ANH-Revision: 1.72 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* aNetHack may be freely redistributed. See license for details. */
5 /* various code that was replicated in *main.c */
7 #include "hack.h"
9 #ifndef NO_SIGNAL
10 #include <signal.h>
11 #endif
13 #ifdef POSITIONBAR
14 STATIC_DCL void NDECL(do_positionbar);
15 #endif
16 STATIC_DCL void FDECL(interrupt_multi, (const char *));
18 void
19 moveloop(resuming)
20 boolean resuming;
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 monscanmove = FALSE;
29 /* Note: these initializers don't do anything except guarantee that
30 we're linked properly.
32 decl_init();
33 monst_init();
34 monstr_init(); /* monster strengths */
35 objects_init();
37 /* if a save file created in normal mode is now being restored in
38 explore mode, treat it as normal restore followed by 'X' command
39 to use up the save file and require confirmation for explore mode */
40 if (resuming && iflags.deferred_X)
41 (void) enter_explore_mode();
43 /* side-effects from the real world */
44 flags.moonphase = phase_of_the_moon();
45 if (flags.moonphase == FULL_MOON) {
46 You("are lucky! Full moon tonight.");
47 change_luck(1);
48 } else if (flags.moonphase == NEW_MOON) {
49 pline("Be careful! New moon tonight.");
51 flags.friday13 = friday_13th();
52 if (flags.friday13) {
53 pline("Watch out! Bad things can happen on Friday the 13th.");
54 change_luck(-1);
57 if (!resuming) { /* new game */
58 context.rndencode = rnd(9000);
59 set_wear((struct obj *) 0); /* for side-effects of starting gear */
60 (void) pickup(1); /* autopickup at initial location */
61 } else { /* restore old game */
62 #ifndef WIN32
63 update_inventory(); /* for perm_invent */
64 #endif
65 read_engr_at(u.ux, u.uy); /* subset of pickup() */
67 #ifdef WIN32
68 update_inventory(); /* for perm_invent */
69 #endif
71 (void) encumber_msg(); /* in case they auto-picked up something */
72 if (defer_see_monsters) {
73 defer_see_monsters = FALSE;
74 see_monsters();
76 initrack();
78 u.uz0.dlevel = u.uz.dlevel;
79 youmonst.movement = NORMAL_SPEED; /* give the hero some movement points */
80 context.move = 0;
82 program_state.in_moveloop = 1;
83 for (;;) {
84 #ifdef SAFERHANGUP
85 if (program_state.done_hup)
86 end_of_input();
87 #endif
88 get_nh_event();
89 #ifdef POSITIONBAR
90 do_positionbar();
91 #endif
93 if (context.move) {
94 /* actual time passed */
95 youmonst.movement -= NORMAL_SPEED;
97 do { /* hero can't move this turn loop */
98 wtcap = encumber_msg();
100 context.mon_moving = TRUE;
101 do {
102 monscanmove = movemon();
103 if (youmonst.movement >= NORMAL_SPEED)
104 break; /* it's now your turn */
105 } while (monscanmove);
106 context.mon_moving = FALSE;
108 if (!monscanmove && youmonst.movement < NORMAL_SPEED) {
109 /* both you and the monsters are out of steam this round
111 /* set up for a new turn */
112 struct monst *mtmp;
113 mcalcdistress(); /* adjust monsters' trap, blind, etc */
115 /* reallocate movement rations to monsters */
116 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
117 mtmp->movement += mcalcmove(mtmp);
119 if (!rn2(u.uevent.udemigod
120 ? 25
121 : (depth(&u.uz) > depth(&stronghold_level))
122 ? 50
123 : 70))
124 (void) makemon((struct permonst *) 0, 0, 0,
125 NO_MM_FLAGS);
127 /* calculate how much time passed. */
128 if (u.usteed && u.umoved) {
129 /* your speed doesn't augment steed's speed */
130 moveamt = mcalcmove(u.usteed);
131 } else {
132 moveamt = youmonst.data->mmove;
134 if (Very_fast) { /* speed boots or potion */
135 /* gain a free action on 2/3 of turns */
136 if (rn2(3) != 0)
137 moveamt += NORMAL_SPEED;
138 } else if (Fast) {
139 /* gain a free action on 1/3 of turns */
140 if (rn2(3) == 0)
141 moveamt += NORMAL_SPEED;
145 switch (wtcap) {
146 case UNENCUMBERED:
147 break;
148 case SLT_ENCUMBER:
149 moveamt -= (moveamt / 4);
150 break;
151 case MOD_ENCUMBER:
152 moveamt -= (moveamt / 2);
153 break;
154 case HVY_ENCUMBER:
155 moveamt -= ((moveamt * 3) / 4);
156 break;
157 case EXT_ENCUMBER:
158 moveamt -= ((moveamt * 7) / 8);
159 break;
160 default:
161 break;
164 youmonst.movement += moveamt;
165 if (youmonst.movement < 0)
166 youmonst.movement = 0;
167 settrack();
169 monstermoves++;
170 moves++;
172 /********************************/
173 /* once-per-turn things go here */
174 /********************************/
176 if (Glib)
177 glibr();
178 nh_timeout();
179 run_regions();
181 if (u.ublesscnt)
182 u.ublesscnt--;
183 if (flags.time && !context.run)
184 context.botl = 1;
186 /* One possible result of prayer is healing. Whether or
187 * not you get healed depends on your current hit points.
188 * If you are allowed to regenerate during the prayer, the
189 * end-of-prayer calculation messes up on this.
190 * Another possible result is rehumanization, which
191 * requires
192 * that encumbrance and movement rate be recalculated.
194 if (u.uinvulnerable) {
195 /* for the moment at least, you're in tiptop shape */
196 wtcap = UNENCUMBERED;
197 } else if (Upolyd && youmonst.data->mlet == S_EEL
198 && !is_pool(u.ux, u.uy)
199 && !Is_waterlevel(&u.uz)) {
200 /* eel out of water loses hp, same as for monsters;
201 as hp gets lower, rate of further loss slows down
203 if (u.mh > 1 && rn2(u.mh) > rn2(8)
204 && (!Half_physical_damage || !(moves % 2L))) {
205 u.mh--;
206 context.botl = 1;
207 } else if (u.mh < 1)
208 rehumanize();
209 } else if (Upolyd && u.mh < u.mhmax) {
210 if (u.mh < 1)
211 rehumanize();
212 else if (Regeneration
213 || (wtcap < MOD_ENCUMBER && !(moves % 20))) {
214 context.botl = 1;
215 u.mh++;
216 if (u.mh >= u.mhmax)
217 interrupt_multi("You are in full health.");
219 } else if (u.uhp < u.uhpmax
220 && (wtcap < MOD_ENCUMBER || !u.umoved
221 || Regeneration)) {
222 if (u.ulevel > 9 && !(moves % 3)) {
223 int heal, Con = (int) ACURR(A_CON);
225 if (Con <= 12) {
226 heal = 1;
227 } else {
228 heal = rnd(Con);
229 if (heal > u.ulevel - 9)
230 heal = u.ulevel - 9;
232 context.botl = 1;
233 u.uhp += heal;
234 if (u.uhp > u.uhpmax)
235 u.uhp = u.uhpmax;
236 if (u.uhp >= u.uhpmax)
237 interrupt_multi("You are in full health.");
238 } else if (Regeneration
239 || (u.ulevel <= 9
240 && !(moves
241 % ((MAXULEV + 12) / (u.ulevel + 2)
242 + 1)))) {
243 context.botl = 1;
244 u.uhp++;
245 if (u.uhp >= u.uhpmax)
246 interrupt_multi("You are in full health.");
250 /* moving around while encumbered is hard work */
251 if (wtcap > MOD_ENCUMBER && u.umoved) {
252 if (!(wtcap < EXT_ENCUMBER ? moves % 30
253 : moves % 10)) {
254 if (Upolyd && u.mh > 1) {
255 u.mh--;
256 } else if (!Upolyd && u.uhp > 1) {
257 u.uhp--;
258 } else {
259 You("pass out from exertion!");
260 exercise(A_CON, FALSE);
261 fall_asleep(-10, FALSE);
266 if ((u.uen < u.uenmax)
267 && ((wtcap < MOD_ENCUMBER
268 && (!(moves % ((MAXULEV + 8 - u.ulevel)
269 * (Role_if(PM_WIZARD) ? 3 : 4)
270 / 6)))) || Energy_regeneration)) {
271 u.uen += rn1(
272 (int) (ACURR(A_WIS) + ACURR(A_INT)) / 15 + 1, 1);
273 if (u.uen > u.uenmax)
274 u.uen = u.uenmax;
275 context.botl = 1;
276 if (u.uen >= u.uenmax)
277 interrupt_multi("You feel full of energy.");
280 if (!u.uinvulnerable) {
281 if (Teleportation && !rn2(85)) {
282 xchar old_ux = u.ux, old_uy = u.uy;
283 tele();
284 if (u.ux != old_ux || u.uy != old_uy) {
285 if (!next_to_u()) {
286 check_leash(old_ux, old_uy);
288 /* clear doagain keystrokes */
289 pushch(0);
290 savech(0);
293 /* delayed change may not be valid anymore */
294 if ((change == 1 && !Polymorph)
295 || (change == 2 && u.ulycn == NON_PM))
296 change = 0;
297 if (Polymorph && !rn2(100))
298 change = 1;
299 else if (u.ulycn >= LOW_PM && !Upolyd
300 && !rn2(80 - (20 * night())))
301 change = 2;
302 if (change && !Unchanging) {
303 if (multi >= 0) {
304 stop_occupation();
305 if (change == 1)
306 polyself(0);
307 else
308 you_were();
309 change = 0;
314 if (Searching && multi >= 0)
315 (void) dosearch0(1);
316 if (Warning)
317 warnreveal();
318 dosounds();
319 do_storms();
320 gethungry();
321 age_spells();
322 exerchk();
323 invault();
324 if (u.uhave.amulet)
325 amulet();
326 if (!rn2(40 + (int) (ACURR(A_DEX) * 3)))
327 u_wipe_engr(rnd(3));
328 if (u.uevent.udemigod && !u.uinvulnerable) {
329 if (u.udg_cnt)
330 u.udg_cnt--;
331 if (!u.udg_cnt) {
332 intervene();
333 u.udg_cnt = rn1(200, 50);
336 restore_attrib();
337 /* underwater and waterlevel vision are done here */
338 if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz))
339 movebubbles();
340 else if (Is_firelevel(&u.uz))
341 fumaroles();
342 else if (Underwater)
343 under_water(0);
344 /* vision while buried done here */
345 else if (u.uburied)
346 under_ground(0);
348 /* when immobile, count is in turns */
349 if (multi < 0) {
350 if (++multi == 0) { /* finished yet? */
351 unmul((char *) 0);
352 /* if unmul caused a level change, take it now */
353 if (u.utotype)
354 deferred_goto();
358 } while (youmonst.movement
359 < NORMAL_SPEED); /* hero can't move loop */
361 /******************************************/
362 /* once-per-hero-took-time things go here */
363 /******************************************/
365 if (context.bypasses)
366 clear_bypasses();
367 if ((u.uhave.amulet || Clairvoyant) && !In_endgame(&u.uz)
368 && !BClairvoyant && !(moves % 15) && !rn2(2))
369 do_vicinity_map((struct obj *) 0);
370 if (u.utrap && u.utraptype == TT_LAVA)
371 sink_into_lava();
372 /* when/if hero escapes from lava, he can't just stay there */
373 else if (!u.umoved)
374 (void) pooleffects(FALSE);
376 } /* actual time passed */
378 /****************************************/
379 /* once-per-player-input things go here */
380 /****************************************/
382 clear_splitobjs();
383 find_ac();
384 if (!context.mv || Blind) {
385 /* redo monsters if hallu or wearing a helm of telepathy */
386 if (Hallucination) { /* update screen randomly */
387 see_monsters();
388 see_objects();
389 see_traps();
390 if (u.uswallow)
391 swallowed(0);
392 } else if (Unblind_telepat) {
393 see_monsters();
394 } else if (Warning || Warn_of_mon)
395 see_monsters();
397 if (vision_full_recalc)
398 vision_recalc(0); /* vision! */
400 if (context.botl || context.botlx) {
401 bot();
402 curs_on_u();
405 context.move = 1;
407 if (multi >= 0 && occupation) {
408 #if defined(MICRO) || defined(WIN32)
409 abort_lev = 0;
410 if (kbhit()) {
411 if ((ch = pgetchar()) == ABORT)
412 abort_lev++;
413 else
414 pushch(ch);
416 if (!abort_lev && (*occupation)() == 0)
417 #else
418 if ((*occupation)() == 0)
419 #endif
420 occupation = 0;
421 if (
422 #if defined(MICRO) || defined(WIN32)
423 abort_lev ||
424 #endif
425 monster_nearby()) {
426 stop_occupation();
427 reset_eat();
429 #if defined(MICRO) || defined(WIN32)
430 if (!(++occtime % 7))
431 display_nhwindow(WIN_MAP, FALSE);
432 #endif
433 continue;
436 if (iflags.sanity_check)
437 sanity_check();
439 #ifdef CLIPPING
440 /* just before rhack */
441 cliparound(u.ux, u.uy);
442 #endif
444 u.umoved = FALSE;
446 if (multi > 0) {
447 lookaround();
448 if (!multi) {
449 /* lookaround may clear multi */
450 context.move = 0;
451 if (flags.time)
452 context.botl = 1;
453 continue;
455 if (context.mv) {
456 if (multi < COLNO && !--multi)
457 context.travel = context.travel1 = context.mv =
458 context.run = 0;
459 domove();
460 } else {
461 --multi;
462 rhack(save_cm);
464 } else if (multi == 0) {
465 #ifdef MAIL
466 ckmailstatus();
467 #endif
468 rhack((char *) 0);
470 if (u.utotype) /* change dungeon level */
471 deferred_goto(); /* after rhack() */
472 /* !context.move here: multiple movement command stopped */
473 else if (flags.time && (!context.move || !context.mv))
474 context.botl = 1;
476 if (vision_full_recalc)
477 vision_recalc(0); /* vision! */
478 /* when running in non-tport mode, this gets done through domove() */
479 if ((!context.run || flags.runmode == RUN_TPORT)
480 && (multi && (!context.travel ? !(multi % 7) : !(moves % 7L)))) {
481 if (flags.time && context.run)
482 context.botl = 1;
483 display_nhwindow(WIN_MAP, FALSE);
488 void
489 stop_occupation()
491 if (occupation) {
492 if (!maybe_finished_meal(TRUE))
493 You("stop %s.", occtxt);
494 occupation = 0;
495 context.botl = 1; /* in case u.uhs changed */
496 nomul(0);
497 pushch(0);
498 } else if (multi >= 0) {
499 nomul(0);
503 void
504 display_gamewindows()
506 WIN_MESSAGE = create_nhwindow(NHW_MESSAGE);
507 #ifdef STATUS_VIA_WINDOWPORT
508 status_initialize(0);
509 #else
510 WIN_STATUS = create_nhwindow(NHW_STATUS);
511 #endif
512 WIN_MAP = create_nhwindow(NHW_MAP);
513 WIN_INVEN = create_nhwindow(NHW_MENU);
514 /* in case of early quit where WIN_INVEN could be destroyed before
515 ever having been used, use it here to pacify the Qt interface */
516 start_menu(WIN_INVEN), end_menu(WIN_INVEN, (char *) 0);
518 #ifdef MAC
519 /* This _is_ the right place for this - maybe we will
520 * have to split display_gamewindows into create_gamewindows
521 * and show_gamewindows to get rid of this ifdef...
523 if (!strcmp(windowprocs.name, "mac"))
524 SanePositions();
525 #endif
528 * The mac port is not DEPENDENT on the order of these
529 * displays, but it looks a lot better this way...
531 #ifndef STATUS_VIA_WINDOWPORT
532 display_nhwindow(WIN_STATUS, FALSE);
533 #endif
534 display_nhwindow(WIN_MESSAGE, FALSE);
535 clear_glyph_buffer();
536 display_nhwindow(WIN_MAP, FALSE);
539 void
540 newgame()
542 int i;
544 #ifdef MFLOPPY
545 gameDiskPrompt();
546 #endif
548 context.botlx = 1;
549 context.ident = 1;
550 context.stethoscope_move = -1L;
551 context.warnlevel = 1;
552 context.next_attrib_check = 600L; /* arbitrary first setting */
553 context.tribute.enabled = TRUE; /* turn on 3.6 tributes */
554 context.tribute.tributesz = sizeof(struct tribute_info);
556 for (i = 0; i < NUMMONS; i++)
557 mvitals[i].mvflags = mons[i].geno & G_NOCORPSE;
559 init_objects(); /* must be before u_init() */
561 flags.pantheon = -1; /* role_init() will reset this */
562 role_init(); /* must be before init_dungeons(), u_init(),
563 * and init_artifacts() */
565 init_dungeons(); /* must be before u_init() to avoid rndmonst()
566 * creating odd monsters for any tins and eggs
567 * in hero's initial inventory */
568 init_artifacts(); /* before u_init() in case $WIZKIT specifies
569 * any artifacts */
570 u_init();
572 #ifndef NO_SIGNAL
573 (void) signal(SIGINT, (SIG_RET_TYPE) done1);
574 #endif
575 #ifdef NEWS
576 if (iflags.news)
577 display_file(NEWS, FALSE);
578 #endif
579 load_qtlist(); /* load up the quest text info */
580 /* quest_init(); -- Now part of role_init() */
582 mklev();
583 u_on_upstairs();
584 if (wizard)
585 obj_delivery(FALSE); /* finish wizkit */
586 vision_reset(); /* set up internals for level (after mklev) */
587 check_special_room(FALSE);
589 if (MON_AT(u.ux, u.uy))
590 mnexto(m_at(u.ux, u.uy));
591 (void) makedog();
592 docrt();
594 if (flags.legacy) {
595 flush_screen(1);
596 com_pager(1);
599 urealtime.realtime = 0L;
600 urealtime.start_timing = getnow();
601 #ifdef INSURANCE
602 save_currentstate();
603 #endif
604 program_state.something_worth_saving++; /* useful data now exists */
606 /* Success! */
607 welcome(TRUE);
608 return;
611 /* show "welcome [back] to anethack" message at program startup */
612 void
613 welcome(new_game)
614 boolean new_game; /* false => restoring an old game */
616 char buf[BUFSZ];
617 boolean currentgend = Upolyd ? u.mfemale : flags.female;
620 * The "welcome back" message always describes your innate form
621 * even when polymorphed or wearing a helm of opposite alignment.
622 * Alignment is shown unconditionally for new games; for restores
623 * it's only shown if it has changed from its original value.
624 * Sex is shown for new games except when it is redundant; for
625 * restores it's only shown if different from its original value.
627 *buf = '\0';
628 if (new_game || u.ualignbase[A_ORIGINAL] != u.ualignbase[A_CURRENT])
629 Sprintf(eos(buf), " %s", align_str(u.ualignbase[A_ORIGINAL]));
630 if (!urole.name.f
631 && (new_game
632 ? (urole.allow & ROLE_GENDMASK) == (ROLE_MALE | ROLE_FEMALE)
633 : currentgend != flags.initgend))
634 Sprintf(eos(buf), " %s", genders[currentgend].adj);
636 pline(new_game ? "%s %s, welcome to aNetHack! You are a%s %s %s."
637 : "%s %s, the%s %s %s, welcome back to aNetHack!",
638 Hello((struct monst *) 0), plname, buf, urace.adj,
639 (currentgend && urole.name.f) ? urole.name.f : urole.name.m);
642 #ifdef POSITIONBAR
643 STATIC_DCL void
644 do_positionbar()
646 static char pbar[COLNO];
647 char *p;
649 p = pbar;
650 /* up stairway */
651 if (upstair.sx
652 && (glyph_to_cmap(level.locations[upstair.sx][upstair.sy].glyph)
653 == S_upstair
654 || glyph_to_cmap(level.locations[upstair.sx][upstair.sy].glyph)
655 == S_upladder)) {
656 *p++ = '<';
657 *p++ = upstair.sx;
659 if (sstairs.sx
660 && (glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph)
661 == S_upstair
662 || glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph)
663 == S_upladder)) {
664 *p++ = '<';
665 *p++ = sstairs.sx;
668 /* down stairway */
669 if (dnstair.sx
670 && (glyph_to_cmap(level.locations[dnstair.sx][dnstair.sy].glyph)
671 == S_dnstair
672 || glyph_to_cmap(level.locations[dnstair.sx][dnstair.sy].glyph)
673 == S_dnladder)) {
674 *p++ = '>';
675 *p++ = dnstair.sx;
677 if (sstairs.sx
678 && (glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph)
679 == S_dnstair
680 || glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph)
681 == S_dnladder)) {
682 *p++ = '>';
683 *p++ = sstairs.sx;
686 /* hero location */
687 if (u.ux) {
688 *p++ = '@';
689 *p++ = u.ux;
691 /* fence post */
692 *p = 0;
694 update_positionbar(pbar);
696 #endif
698 STATIC_DCL void
699 interrupt_multi(msg)
700 const char *msg;
702 if (multi > 0 && !context.travel) {
703 nomul(0);
704 if (flags.verbose && msg)
705 Norep("%s", msg);
710 /*allmain.c*/