1 /* NetHack 3.6 allmain.c $NHDT-Date: 1555552624 2019/04/18 01:57:04 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.100 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Robert Patrick Rankin, 2012. */
4 /* NetHack may be freely redistributed. See license for details. */
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2019 */
9 /* JNetHack may be freely redistributed. See license for details. */
11 /* various code that was replicated in *main.c */
21 STATIC_DCL void NDECL(do_positionbar);
23 STATIC_DCL void FDECL(regen_hp, (int));
24 STATIC_DCL void FDECL(interrupt_multi, (const char *));
25 STATIC_DCL void FDECL(debug_fields, (const char *));
31 #if defined(MICRO) || defined(WIN32)
35 int moveamt = 0, wtcap = 0, change = 0;
36 boolean monscanmove = FALSE;
38 /* Note: these initializers don't do anything except guarantee that
39 we're linked properly.
45 /* if a save file created in normal mode is now being restored in
46 explore mode, treat it as normal restore followed by 'X' command
47 to use up the save file and require confirmation for explore mode */
48 if (resuming && iflags.deferred_X)
49 (void) enter_explore_mode();
51 /* side-effects from the real world */
52 flags.moonphase = phase_of_the_moon();
53 if (flags.moonphase == FULL_MOON) {
55 You("are lucky! Full moon tonight.");
57 pline("
\83\89\83b
\83L
\81[
\81I
\8d¡
\94Ó
\82Í
\96\9e\8c\8e\82¾
\81D");
59 } else if (flags.moonphase == NEW_MOON) {
61 pline("Be careful! New moon tonight.");
63 pline("
\92\8d\88Ó
\82µ
\82ë
\81I
\8d¡
\94Ó
\82Í
\90V
\8c\8e\82¾
\81D");
65 flags.friday13 = friday_13th();
68 pline("Watch out! Bad things can happen on Friday the 13th.");
70 pline("
\97p
\90S
\82µ
\82ë
\81I
\82P
\82R
\93ú
\82Ì
\8bà
\97j
\93ú
\82É
\82Í
\82æ
\82
\82È
\82¢
\82±
\82Æ
\82ª
\82 \82é
\81D") ;
74 if (!resuming) { /* new game */
75 context.rndencode = rnd(9000);
76 set_wear((struct obj *) 0); /* for side-effects of starting gear */
77 (void) pickup(1); /* autopickup at initial location */
79 context.botlx = TRUE; /* for STATUS_HILITES */
80 update_inventory(); /* for perm_invent */
81 if (resuming) { /* restoring old game */
82 read_engr_at(u.ux, u.uy); /* subset of pickup() */
85 (void) encumber_msg(); /* in case they auto-picked up something */
86 if (defer_see_monsters) {
87 defer_see_monsters = FALSE;
92 u.uz0.dlevel = u.uz.dlevel;
93 youmonst.movement = NORMAL_SPEED; /* give the hero some movement points */
96 program_state.in_moveloop = 1;
99 if (program_state.done_hup)
108 /* actual time passed */
109 youmonst.movement -= NORMAL_SPEED;
111 do { /* hero can't move this turn loop */
112 wtcap = encumber_msg();
114 context.mon_moving = TRUE;
116 monscanmove = movemon();
117 if (youmonst.movement >= NORMAL_SPEED)
118 break; /* it's now your turn */
119 } while (monscanmove);
120 context.mon_moving = FALSE;
122 if (!monscanmove && youmonst.movement < NORMAL_SPEED) {
123 /* both hero and monsters are out of steam this round */
126 /* set up for a new turn */
127 mcalcdistress(); /* adjust monsters' trap, blind, etc */
129 /* reallocate movement rations to monsters; don't need
130 to skip dead monsters here because they will have
131 been purged at end of their previous round of moving */
132 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
133 mtmp->movement += mcalcmove(mtmp);
135 /* occasionally add another monster; since this takes
136 place after movement has been allotted, the new
137 monster effectively loses its first turn */
138 if (!rn2(u.uevent.udemigod ? 25
139 : (depth(&u.uz) > depth(&stronghold_level)) ? 50
141 (void) makemon((struct permonst *) 0, 0, 0,
144 /* calculate how much time passed. */
145 if (u.usteed && u.umoved) {
146 /* your speed doesn't augment steed's speed */
147 moveamt = mcalcmove(u.usteed);
149 moveamt = youmonst.data->mmove;
151 if (Very_fast) { /* speed boots, potion, or spell */
152 /* gain a free action on 2/3 of turns */
154 moveamt += NORMAL_SPEED;
155 } else if (Fast) { /* intrinsic */
156 /* gain a free action on 1/3 of turns */
158 moveamt += NORMAL_SPEED;
166 moveamt -= (moveamt / 4);
169 moveamt -= (moveamt / 2);
172 moveamt -= ((moveamt * 3) / 4);
175 moveamt -= ((moveamt * 7) / 8);
181 youmonst.movement += moveamt;
182 if (youmonst.movement < 0)
183 youmonst.movement = 0;
189 /********************************/
190 /* once-per-turn things go here */
191 /********************************/
200 if (flags.time && !context.run)
201 iflags.time_botl = TRUE;
203 /* One possible result of prayer is healing. Whether or
204 * not you get healed depends on your current hit points.
205 * If you are allowed to regenerate during the prayer,
206 * the end-of-prayer calculation messes up on this.
207 * Another possible result is rehumanization, which
208 * requires that encumbrance and movement rate be
211 if (u.uinvulnerable) {
212 /* for the moment at least, you're in tiptop shape */
213 wtcap = UNENCUMBERED;
214 } else if (!Upolyd ? (u.uhp < u.uhpmax)
216 || youmonst.data->mlet == S_EEL)) {
221 /* moving around while encumbered is hard work */
222 if (wtcap > MOD_ENCUMBER && u.umoved) {
223 if (!(wtcap < EXT_ENCUMBER ? moves % 30
225 if (Upolyd && u.mh > 1) {
228 } else if (!Upolyd && u.uhp > 1) {
233 You("pass out from exertion!");
235 pline("
\94æ
\98J
\82Å
\88Ó
\8e¯
\82ð
\8e¸
\82Á
\82½
\81I");
236 exercise(A_CON, FALSE);
237 fall_asleep(-10, FALSE);
243 && ((wtcap < MOD_ENCUMBER
244 && (!(moves % ((MAXULEV + 8 - u.ulevel)
245 * (Role_if(PM_WIZARD) ? 3 : 4)
246 / 6)))) || Energy_regeneration)) {
248 (int) (ACURR(A_WIS) + ACURR(A_INT)) / 15 + 1, 1);
249 if (u.uen > u.uenmax)
252 if (u.uen == u.uenmax)
254 interrupt_multi("You feel full of energy.");
256 interrupt_multi("
\83G
\83l
\83\8b\83M
\81[
\82ª
\89ñ
\95\9c\82µ
\82½
\81D");
259 if (!u.uinvulnerable) {
260 if (Teleportation && !rn2(85)) {
261 xchar old_ux = u.ux, old_uy = u.uy;
264 if (u.ux != old_ux || u.uy != old_uy) {
266 check_leash(old_ux, old_uy);
268 /* clear doagain keystrokes */
273 /* delayed change may not be valid anymore */
274 if ((change == 1 && !Polymorph)
275 || (change == 2 && u.ulycn == NON_PM))
277 if (Polymorph && !rn2(100))
279 else if (u.ulycn >= LOW_PM && !Upolyd
280 && !rn2(80 - (20 * night())))
282 if (change && !Unchanging) {
294 if (Searching && multi >= 0)
307 if (!rn2(40 + (int) (ACURR(A_DEX) * 3)))
309 if (u.uevent.udemigod && !u.uinvulnerable) {
314 u.udg_cnt = rn1(200, 50);
318 /* underwater and waterlevel vision are done here */
319 if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz))
321 else if (Is_firelevel(&u.uz))
325 /* vision while buried done here */
329 /* when immobile, count is in turns */
331 if (++multi == 0) { /* finished yet? */
333 /* if unmul caused a level change, take it now */
339 } while (youmonst.movement < NORMAL_SPEED); /* hero can't move */
341 /******************************************/
342 /* once-per-hero-took-time things go here */
343 /******************************************/
345 #ifdef STATUS_HILITES
346 if (iflags.hilite_delta)
347 status_eval_next_unhilite();
349 if (context.bypasses)
351 if ((u.uhave.amulet || Clairvoyant) && !In_endgame(&u.uz)
352 && !BClairvoyant && !(moves % 15) && !rn2(2))
353 do_vicinity_map((struct obj *) 0);
354 if (u.utrap && u.utraptype == TT_LAVA)
356 /* when/if hero escapes from lava, he can't just stay there */
358 (void) pooleffects(FALSE);
360 } /* actual time passed */
362 /****************************************/
363 /* once-per-player-input things go here */
364 /****************************************/
368 if (!context.mv || Blind) {
369 /* redo monsters if hallu or wearing a helm of telepathy */
370 if (Hallucination) { /* update screen randomly */
376 } else if (Unblind_telepat) {
378 } else if (Warning || Warn_of_mon)
381 if (vision_full_recalc)
382 vision_recalc(0); /* vision! */
384 if (context.botl || context.botlx) {
387 } else if (iflags.time_botl) {
394 if (multi >= 0 && occupation) {
395 #if defined(MICRO) || defined(WIN32)
398 if ((ch = pgetchar()) == ABORT)
403 if (!abort_lev && (*occupation)() == 0)
405 if ((*occupation)() == 0)
409 #if defined(MICRO) || defined(WIN32)
416 #if defined(MICRO) || defined(WIN32)
417 if (!(++occtime % 7))
418 display_nhwindow(WIN_MAP, FALSE);
423 if (iflags.sanity_check || iflags.debug_fuzzer)
427 /* just before rhack */
428 cliparound(u.ux, u.uy);
436 /* lookaround may clear multi */
443 if (multi < COLNO && !--multi)
444 context.travel = context.travel1 = context.mv =
451 } else if (multi == 0) {
457 if (u.utotype) /* change dungeon level */
458 deferred_goto(); /* after rhack() */
459 /* !context.move here: multiple movement command stopped */
460 else if (flags.time && (!context.move || !context.mv))
463 if (vision_full_recalc)
464 vision_recalc(0); /* vision! */
465 /* when running in non-tport mode, this gets done through domove() */
466 if ((!context.run || flags.runmode == RUN_TPORT)
467 && (multi && (!context.travel ? !(multi % 7) : !(moves % 7L)))) {
468 if (flags.time && context.run)
470 /* [should this be flush_screen() instead?] */
471 display_nhwindow(WIN_MAP, FALSE);
476 /* maybe recover some lost health (or lose some when an eel out of water) */
482 boolean reached_full = FALSE,
483 encumbrance_ok = (wtcap < MOD_ENCUMBER || !u.umoved);
486 if (u.mh < 1) { /* shouldn't happen... */
488 } else if (youmonst.data->mlet == S_EEL
489 && !is_pool(u.ux, u.uy) && !Is_waterlevel(&u.uz)) {
490 /* eel out of water loses hp, similar to monster eels;
491 as hp gets lower, rate of further loss slows down */
492 if (u.mh > 1 && !Regeneration && rn2(u.mh) > rn2(8)
493 && (!Half_physical_damage || !(moves % 2L)))
495 } else if (u.mh < u.mhmax) {
496 if (Regeneration || (encumbrance_ok && !(moves % 20L)))
502 reached_full = (u.mh == u.mhmax);
507 /* [when this code was in-line within moveloop(), there was
508 no !Upolyd check here, so poly'd hero recovered lost u.uhp
509 once u.mh reached u.mhmax; that may have been convenient
510 for the player, but it didn't make sense for gameplay...] */
511 if (u.uhp < u.uhpmax && (encumbrance_ok || Regeneration)) {
514 int Con = (int) ACURR(A_CON);
520 if (heal > u.ulevel - 9)
524 } else { /* u.ulevel <= 9 */
525 if (!(moves % (long) ((MAXULEV + 12) / (u.ulevel + 2) + 1)))
528 if (Regeneration && !heal)
534 if (u.uhp > u.uhpmax)
536 /* stop voluntary multi-turn activity if now fully healed */
537 reached_full = (u.uhp == u.uhpmax);
544 interrupt_multi("You are in full health.");
546 interrupt_multi("
\91Ì
\97Í
\82ª
\89ñ
\95\9c\82µ
\82½
\81D");
553 if (!maybe_finished_meal(TRUE))
555 You("stop %s.", occtxt);
557 You("%s
\82Ì
\82ð
\92\86\92f
\82µ
\82½
\81D", occtxt);
559 context.botl = TRUE; /* in case u.uhs changed */
562 } else if (multi >= 0) {
568 display_gamewindows()
570 WIN_MESSAGE = create_nhwindow(NHW_MESSAGE);
571 if (VIA_WINDOWPORT()) {
572 status_initialize(0);
574 WIN_STATUS = create_nhwindow(NHW_STATUS);
576 WIN_MAP = create_nhwindow(NHW_MAP);
577 WIN_INVEN = create_nhwindow(NHW_MENU);
578 /* in case of early quit where WIN_INVEN could be destroyed before
579 ever having been used, use it here to pacify the Qt interface */
580 start_menu(WIN_INVEN), end_menu(WIN_INVEN, (char *) 0);
583 /* This _is_ the right place for this - maybe we will
584 * have to split display_gamewindows into create_gamewindows
585 * and show_gamewindows to get rid of this ifdef...
587 if (!strcmp(windowprocs.name, "mac"))
592 * The mac port is not DEPENDENT on the order of these
593 * displays, but it looks a lot better this way...
595 #ifndef STATUS_HILITES
596 display_nhwindow(WIN_STATUS, FALSE);
598 display_nhwindow(WIN_MESSAGE, FALSE);
599 clear_glyph_buffer();
600 display_nhwindow(WIN_MAP, FALSE);
612 context.botlx = TRUE;
614 context.stethoscope_move = -1L;
615 context.warnlevel = 1;
616 context.next_attrib_check = 600L; /* arbitrary first setting */
617 context.tribute.enabled = TRUE; /* turn on 3.6 tributes */
618 context.tribute.tributesz = sizeof(struct tribute_info);
620 for (i = LOW_PM; i < NUMMONS; i++)
621 mvitals[i].mvflags = mons[i].geno & G_NOCORPSE;
623 init_objects(); /* must be before u_init() */
625 flags.pantheon = -1; /* role_init() will reset this */
626 role_init(); /* must be before init_dungeons(), u_init(),
627 * and init_artifacts() */
629 init_dungeons(); /* must be before u_init() to avoid rndmonst()
630 * creating odd monsters for any tins and eggs
631 * in hero's initial inventory */
632 init_artifacts(); /* before u_init() in case $WIZKIT specifies
637 (void) signal(SIGINT, (SIG_RET_TYPE) done1);
641 display_file(NEWS, FALSE);
643 load_qtlist(); /* load up the quest text info */
644 /* quest_init(); -- Now part of role_init() */
649 obj_delivery(FALSE); /* finish wizkit */
650 vision_reset(); /* set up internals for level (after mklev) */
651 check_special_room(FALSE);
653 if (MON_AT(u.ux, u.uy))
654 mnexto(m_at(u.ux, u.uy));
663 urealtime.realtime = 0L;
664 urealtime.start_timing = getnow();
668 program_state.something_worth_saving++; /* useful data now exists */
675 /* show "welcome [back] to nethack" message at program startup */
678 boolean new_game; /* false => restoring an old game */
681 boolean currentgend = Upolyd ? u.mfemale : flags.female;
683 /* skip "welcome back" if restoring a doomed character */
684 if (!new_game && Upolyd && ugenocided()) {
685 /* death via self-genocide is pending */
687 pline("You're back, but you still feel %s inside.", udeadinside());
689 pline("
\82 \82È
\82½
\82Í
\8bA
\82Á
\82Ä
\82«
\82½
\82ª
\81C
\8d°
\82ª%s
\82Ü
\82Ü
\82¾
\81D", udeadinside());
694 * The "welcome back" message always describes your innate form
695 * even when polymorphed or wearing a helm of opposite alignment.
696 * Alignment is shown unconditionally for new games; for restores
697 * it's only shown if it has changed from its original value.
698 * Sex is shown for new games except when it is redundant; for
699 * restores it's only shown if different from its original value.
702 if (new_game || u.ualignbase[A_ORIGINAL] != u.ualignbase[A_CURRENT])
704 Sprintf(eos(buf), " %s", align_str(u.ualignbase[A_ORIGINAL]));
706 Sprintf(eos(buf), "%s", align_str(u.ualignbase[A_ORIGINAL]));
709 ? (urole.allow & ROLE_GENDMASK) == (ROLE_MALE | ROLE_FEMALE)
710 : currentgend != flags.initgend))
712 Sprintf(eos(buf), " %s", genders[currentgend].adj);
714 Sprintf(eos(buf), "
\82Ì%s", genders[currentgend].adj);
717 pline(new_game ? "%s %s, welcome to NetHack! You are a%s %s %s."
718 : "%s %s, the%s %s %s, welcome back to NetHack!",
719 Hello((struct monst *) 0), plname, buf, urace.adj,
720 (currentgend && urole.name.f) ? urole.name.f : urole.name.m);
723 pline("%s
\81CNetHack
\82Ì
\90¢
\8aE
\82Ö
\81I
\82±
\82Ì
\83Q
\81[
\83\80\82Å
\82Í
\82 \82È
\82½
\82Í%s%s(%s)
\82¾
\81D",
724 Hello((struct monst *) 0), urace.adj,
725 (currentgend && urole.name.f) ? urole.name.f : urole.name.m,
728 pline("%s
\81CNetHack
\82Ì
\90¢
\8aE
\82Ö
\81I
\82 \82È
\82½
\82Í%s%s
\82¾
\81I",
729 Hello((struct monst *) 0), urace.adj,
730 (currentgend && urole.name.f) ? urole.name.f : urole.name.m);
739 static char pbar[COLNO];
745 && (glyph_to_cmap(level.locations[upstair.sx][upstair.sy].glyph)
747 || glyph_to_cmap(level.locations[upstair.sx][upstair.sy].glyph)
753 && (glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph)
755 || glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph)
763 && (glyph_to_cmap(level.locations[dnstair.sx][dnstair.sy].glyph)
765 || glyph_to_cmap(level.locations[dnstair.sx][dnstair.sy].glyph)
771 && (glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph)
773 || glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph)
787 update_positionbar(pbar);
795 if (multi > 0 && !context.travel && !context.run) {
797 if (flags.verbose && msg)
803 * Argument processing helpers - for xxmain() to share
806 * These should return TRUE if the argument matched,
807 * whether the processing of the argument was
810 * Most of these do their thing, then after returning
811 * to xxmain(), the code exits without starting a game.
815 static struct early_opt earlyopts[] = {
816 {ARG_DEBUG, "debug", 5, TRUE},
817 {ARG_VERSION, "version", 4, TRUE},
819 {ARG_WINDOWS, "windows", 4, TRUE},
824 extern int FDECL(windows_early_options, (const char *));
830 * 1 = found and skip past this argument
831 * 2 = found and trigger immediate exit
835 argcheck(argc, argv, e_arg)
841 boolean match = FALSE;
842 char *userea = (char *)0;
843 const char *dashdash = "";
845 for (idx = 0; idx < SIZE(earlyopts); idx++) {
846 if (earlyopts[idx].e == e_arg)
849 if ((idx >= SIZE(earlyopts)) || (argc <= 1))
852 for (i = 0; i < argc; ++i) {
853 if (argv[i][0] != '-')
855 if (argv[i][1] == '-') {
856 userea = &argv[i][2];
859 userea = &argv[i][1];
861 match = match_optname(userea, earlyopts[idx].name,
862 earlyopts[idx].minlength,
863 earlyopts[idx].valallowed);
868 const char *extended_opt = index(userea, ':');
871 extended_opt = index(userea, '=');
876 debug_fields(extended_opt);
880 boolean insert_into_pastebuf = FALSE;
884 if (match_optname(extended_opt, "paste", 5, FALSE)) {
885 insert_into_pastebuf = TRUE;
888 "-%sversion can only be extended with -%sversion:paste.\n",
893 early_version_info(insert_into_pastebuf);
900 return windows_early_options(extended_opt);
912 * These are internal controls to aid developers with
913 * testing and debugging particular aspects of the code.
914 * They are not player options and the only place they
915 * are documented is right here. No gameplay is altered.
917 * test - test whether this parser is working
919 * immediateflips - WIN32: turn off display performance
920 * optimization so that display output
921 * can be debugged without buffering.
928 boolean negated = FALSE;
930 while ((op = index(opts, ',')) != 0) {
935 if (strlen(opts) > BUFSZ / 2)
939 /* strip leading and trailing white space */
940 while (isspace((uchar) *opts))
942 op = eos((char *) opts);
943 while (--op >= opts && isspace((uchar) *op))
950 while ((*opts == '!') || !strncmpi(opts, "no", 2)) {
957 if (match_optname(opts, "test", 4, FALSE))
958 iflags.debug.test = negated ? FALSE : TRUE;
960 if (match_optname(opts, "ttystatus", 9, FALSE))
961 iflags.debug.ttystatus = negated ? FALSE : TRUE;
964 if (match_optname(opts, "immediateflips", 14, FALSE))
965 iflags.debug.immediateflips = negated ? FALSE : TRUE;