1 /* NetHack 3.6 allmain.c $NHDT-Date: 1518193644 2018/02/09 16:27:24 $ $NHDT-Branch: githash $:$NHDT-Revision: 1.86 $ */
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-2018 */
9 /* JNetHack may be freely redistributed. See license for details. */
11 /* various code that was replicated in *main.c */
20 STATIC_DCL void NDECL(do_positionbar);
22 STATIC_DCL void FDECL(regen_hp, (int));
23 STATIC_DCL void FDECL(interrupt_multi, (const char *));
29 #if defined(MICRO) || defined(WIN32)
33 int moveamt = 0, wtcap = 0, change = 0;
34 boolean monscanmove = FALSE;
36 /* Note: these initializers don't do anything except guarantee that
37 we're linked properly.
41 monstr_init(); /* monster strengths */
44 /* if a save file created in normal mode is now being restored in
45 explore mode, treat it as normal restore followed by 'X' command
46 to use up the save file and require confirmation for explore mode */
47 if (resuming && iflags.deferred_X)
48 (void) enter_explore_mode();
50 /* side-effects from the real world */
51 flags.moonphase = phase_of_the_moon();
52 if (flags.moonphase == FULL_MOON) {
54 You("are lucky! Full moon tonight.");
56 pline("
\83\89\83b
\83L
\81[
\81I
\8d¡
\94Ó
\82Í
\96\9e\8c\8e\82¾
\81D");
58 } else if (flags.moonphase == NEW_MOON) {
60 pline("Be careful! New moon tonight.");
62 pline("
\92\8d\88Ó
\82µ
\82ë
\81I
\8d¡
\94Ó
\82Í
\90V
\8c\8e\82¾
\81D");
64 flags.friday13 = friday_13th();
67 pline("Watch out! Bad things can happen on Friday the 13th.");
69 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") ;
73 if (!resuming) { /* new game */
74 context.rndencode = rnd(9000);
75 set_wear((struct obj *) 0); /* for side-effects of starting gear */
76 (void) pickup(1); /* autopickup at initial location */
78 context.botlx = TRUE; /* for STATUS_HILITES */
79 update_inventory(); /* for perm_invent */
80 if (resuming) { /* restoring old game */
81 read_engr_at(u.ux, u.uy); /* subset of pickup() */
84 (void) encumber_msg(); /* in case they auto-picked up something */
85 if (defer_see_monsters) {
86 defer_see_monsters = FALSE;
91 u.uz0.dlevel = u.uz.dlevel;
92 youmonst.movement = NORMAL_SPEED; /* give the hero some movement points */
95 program_state.in_moveloop = 1;
98 if (program_state.done_hup)
107 /* actual time passed */
108 youmonst.movement -= NORMAL_SPEED;
110 do { /* hero can't move this turn loop */
111 wtcap = encumber_msg();
113 context.mon_moving = TRUE;
115 monscanmove = movemon();
116 if (youmonst.movement >= NORMAL_SPEED)
117 break; /* it's now your turn */
118 } while (monscanmove);
119 context.mon_moving = FALSE;
121 if (!monscanmove && youmonst.movement < NORMAL_SPEED) {
122 /* both you and the monsters are out of steam this round
124 /* set up for a new turn */
126 mcalcdistress(); /* adjust monsters' trap, blind, etc */
128 /* reallocate movement rations to monsters */
129 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
130 mtmp->movement += mcalcmove(mtmp);
132 if (!rn2(u.uevent.udemigod
134 : (depth(&u.uz) > depth(&stronghold_level))
137 (void) makemon((struct permonst *) 0, 0, 0,
140 /* calculate how much time passed. */
141 if (u.usteed && u.umoved) {
142 /* your speed doesn't augment steed's speed */
143 moveamt = mcalcmove(u.usteed);
145 moveamt = youmonst.data->mmove;
147 if (Very_fast) { /* speed boots or potion */
148 /* gain a free action on 2/3 of turns */
150 moveamt += NORMAL_SPEED;
152 /* gain a free action on 1/3 of turns */
154 moveamt += NORMAL_SPEED;
162 moveamt -= (moveamt / 4);
165 moveamt -= (moveamt / 2);
168 moveamt -= ((moveamt * 3) / 4);
171 moveamt -= ((moveamt * 7) / 8);
177 youmonst.movement += moveamt;
178 if (youmonst.movement < 0)
179 youmonst.movement = 0;
185 /********************************/
186 /* once-per-turn things go here */
187 /********************************/
196 if (flags.time && !context.run)
199 /* One possible result of prayer is healing. Whether or
200 * not you get healed depends on your current hit points.
201 * If you are allowed to regenerate during the prayer,
202 * the end-of-prayer calculation messes up on this.
203 * Another possible result is rehumanization, which
204 * requires that encumbrance and movement rate be
207 if (u.uinvulnerable) {
208 /* for the moment at least, you're in tiptop shape */
209 wtcap = UNENCUMBERED;
210 } else if (!Upolyd ? (u.uhp < u.uhpmax)
212 || youmonst.data->mlet == S_EEL)) {
217 /* moving around while encumbered is hard work */
218 if (wtcap > MOD_ENCUMBER && u.umoved) {
219 if (!(wtcap < EXT_ENCUMBER ? moves % 30
221 if (Upolyd && u.mh > 1) {
223 } else if (!Upolyd && u.uhp > 1) {
227 You("pass out from exertion!");
229 pline("
\94æ
\98J
\82Å
\88Ó
\8e¯
\82ð
\8e¸
\82Á
\82½
\81I");
230 exercise(A_CON, FALSE);
231 fall_asleep(-10, FALSE);
237 && ((wtcap < MOD_ENCUMBER
238 && (!(moves % ((MAXULEV + 8 - u.ulevel)
239 * (Role_if(PM_WIZARD) ? 3 : 4)
240 / 6)))) || Energy_regeneration)) {
242 (int) (ACURR(A_WIS) + ACURR(A_INT)) / 15 + 1, 1);
243 if (u.uen > u.uenmax)
246 if (u.uen == u.uenmax)
248 interrupt_multi("You feel full of energy.");
250 interrupt_multi("
\83G
\83l
\83\8b\83M
\81[
\82ª
\89ñ
\95\9c\82µ
\82½
\81D");
253 if (!u.uinvulnerable) {
254 if (Teleportation && !rn2(85)) {
255 xchar old_ux = u.ux, old_uy = u.uy;
257 if (u.ux != old_ux || u.uy != old_uy) {
259 check_leash(old_ux, old_uy);
261 /* clear doagain keystrokes */
266 /* delayed change may not be valid anymore */
267 if ((change == 1 && !Polymorph)
268 || (change == 2 && u.ulycn == NON_PM))
270 if (Polymorph && !rn2(100))
272 else if (u.ulycn >= LOW_PM && !Upolyd
273 && !rn2(80 - (20 * night())))
275 if (change && !Unchanging) {
287 if (Searching && multi >= 0)
300 if (!rn2(40 + (int) (ACURR(A_DEX) * 3)))
302 if (u.uevent.udemigod && !u.uinvulnerable) {
307 u.udg_cnt = rn1(200, 50);
311 /* underwater and waterlevel vision are done here */
312 if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz))
314 else if (Is_firelevel(&u.uz))
318 /* vision while buried done here */
322 /* when immobile, count is in turns */
324 if (++multi == 0) { /* finished yet? */
326 /* if unmul caused a level change, take it now */
332 } while (youmonst.movement
333 < NORMAL_SPEED); /* hero can't move loop */
335 /******************************************/
336 /* once-per-hero-took-time things go here */
337 /******************************************/
339 status_eval_next_unhilite();
340 if (context.bypasses)
342 if ((u.uhave.amulet || Clairvoyant) && !In_endgame(&u.uz)
343 && !BClairvoyant && !(moves % 15) && !rn2(2))
344 do_vicinity_map((struct obj *) 0);
345 if (u.utrap && u.utraptype == TT_LAVA)
347 /* when/if hero escapes from lava, he can't just stay there */
349 (void) pooleffects(FALSE);
351 } /* actual time passed */
353 /****************************************/
354 /* once-per-player-input things go here */
355 /****************************************/
359 if (!context.mv || Blind) {
360 /* redo monsters if hallu or wearing a helm of telepathy */
361 if (Hallucination) { /* update screen randomly */
367 } else if (Unblind_telepat) {
369 } else if (Warning || Warn_of_mon)
372 if (vision_full_recalc)
373 vision_recalc(0); /* vision! */
375 if (context.botl || context.botlx) {
382 if (multi >= 0 && occupation) {
383 #if defined(MICRO) || defined(WIN32)
386 if ((ch = pgetchar()) == ABORT)
391 if (!abort_lev && (*occupation)() == 0)
393 if ((*occupation)() == 0)
397 #if defined(MICRO) || defined(WIN32)
404 #if defined(MICRO) || defined(WIN32)
405 if (!(++occtime % 7))
406 display_nhwindow(WIN_MAP, FALSE);
411 if (iflags.sanity_check)
415 /* just before rhack */
416 cliparound(u.ux, u.uy);
424 /* lookaround may clear multi */
431 if (multi < COLNO && !--multi)
432 context.travel = context.travel1 = context.mv =
439 } else if (multi == 0) {
445 if (u.utotype) /* change dungeon level */
446 deferred_goto(); /* after rhack() */
447 /* !context.move here: multiple movement command stopped */
448 else if (flags.time && (!context.move || !context.mv))
451 if (vision_full_recalc)
452 vision_recalc(0); /* vision! */
453 /* when running in non-tport mode, this gets done through domove() */
454 if ((!context.run || flags.runmode == RUN_TPORT)
455 && (multi && (!context.travel ? !(multi % 7) : !(moves % 7L)))) {
456 if (flags.time && context.run)
458 display_nhwindow(WIN_MAP, FALSE);
463 /* maybe recover some lost health (or lose some when an eel out of water) */
469 boolean reached_full = FALSE,
470 encumbrance_ok = (wtcap < MOD_ENCUMBER || !u.umoved);
473 if (u.mh < 1) { /* shouldn't happen... */
475 } else if (youmonst.data->mlet == S_EEL
476 && !is_pool(u.ux, u.uy) && !Is_waterlevel(&u.uz)) {
477 /* eel out of water loses hp, similar to monster eels;
478 as hp gets lower, rate of further loss slows down */
479 if (u.mh > 1 && !Regeneration && rn2(u.mh) > rn2(8)
480 && (!Half_physical_damage || !(moves % 2L)))
482 } else if (u.mh < u.mhmax) {
483 if (Regeneration || (encumbrance_ok && !(moves % 20L)))
489 reached_full = (u.mh == u.mhmax);
494 /* [when this code was in-line within moveloop(), there was
495 no !Upolyd check here, so poly'd hero recovered lost u.uhp
496 once u.mh reached u.mhmax; that may have been convenient
497 for the player, but it didn't make sense for gameplay...] */
498 if (u.uhp < u.uhpmax && (encumbrance_ok || Regeneration)) {
501 int Con = (int) ACURR(A_CON);
507 if (heal > u.ulevel - 9)
511 } else { /* u.ulevel <= 9 */
512 if (!(moves % (long) ((MAXULEV + 12) / (u.ulevel + 2) + 1)))
515 if (Regeneration && !heal)
521 if (u.uhp > u.uhpmax)
523 /* stop voluntary multi-turn activity if now fully healed */
524 reached_full = (u.uhp == u.uhpmax);
531 interrupt_multi("You are in full health.");
533 interrupt_multi("
\91Ì
\97Í
\82ª
\89ñ
\95\9c\82µ
\82½
\81D");
540 if (!maybe_finished_meal(TRUE))
542 You("stop %s.", occtxt);
544 You("%s
\82Ì
\82ð
\92\86\92f
\82µ
\82½
\81D", occtxt);
546 context.botl = 1; /* in case u.uhs changed */
549 } else if (multi >= 0) {
555 display_gamewindows()
557 WIN_MESSAGE = create_nhwindow(NHW_MESSAGE);
558 #ifdef STATUS_HILITES
559 status_initialize(0);
561 WIN_STATUS = create_nhwindow(NHW_STATUS);
563 WIN_MAP = create_nhwindow(NHW_MAP);
564 WIN_INVEN = create_nhwindow(NHW_MENU);
565 /* in case of early quit where WIN_INVEN could be destroyed before
566 ever having been used, use it here to pacify the Qt interface */
567 start_menu(WIN_INVEN), end_menu(WIN_INVEN, (char *) 0);
570 /* This _is_ the right place for this - maybe we will
571 * have to split display_gamewindows into create_gamewindows
572 * and show_gamewindows to get rid of this ifdef...
574 if (!strcmp(windowprocs.name, "mac"))
579 * The mac port is not DEPENDENT on the order of these
580 * displays, but it looks a lot better this way...
582 #ifndef STATUS_HILITES
583 display_nhwindow(WIN_STATUS, FALSE);
585 display_nhwindow(WIN_MESSAGE, FALSE);
586 clear_glyph_buffer();
587 display_nhwindow(WIN_MAP, FALSE);
601 context.stethoscope_move = -1L;
602 context.warnlevel = 1;
603 context.next_attrib_check = 600L; /* arbitrary first setting */
604 context.tribute.enabled = TRUE; /* turn on 3.6 tributes */
605 context.tribute.tributesz = sizeof(struct tribute_info);
607 for (i = LOW_PM; i < NUMMONS; i++)
608 mvitals[i].mvflags = mons[i].geno & G_NOCORPSE;
610 init_objects(); /* must be before u_init() */
612 flags.pantheon = -1; /* role_init() will reset this */
613 role_init(); /* must be before init_dungeons(), u_init(),
614 * and init_artifacts() */
616 init_dungeons(); /* must be before u_init() to avoid rndmonst()
617 * creating odd monsters for any tins and eggs
618 * in hero's initial inventory */
619 init_artifacts(); /* before u_init() in case $WIZKIT specifies
624 (void) signal(SIGINT, (SIG_RET_TYPE) done1);
628 display_file(NEWS, FALSE);
630 load_qtlist(); /* load up the quest text info */
631 /* quest_init(); -- Now part of role_init() */
636 obj_delivery(FALSE); /* finish wizkit */
637 vision_reset(); /* set up internals for level (after mklev) */
638 check_special_room(FALSE);
640 if (MON_AT(u.ux, u.uy))
641 mnexto(m_at(u.ux, u.uy));
650 urealtime.realtime = 0L;
651 urealtime.start_timing = getnow();
655 program_state.something_worth_saving++; /* useful data now exists */
662 /* show "welcome [back] to nethack" message at program startup */
665 boolean new_game; /* false => restoring an old game */
668 boolean currentgend = Upolyd ? u.mfemale : flags.female;
670 /* skip "welcome back" if restoring a doomed character */
671 if (!new_game && Upolyd && ugenocided()) {
672 /* death via self-genocide is pending */
674 pline("You're back, but you still feel %s inside.", udeadinside());
676 pline("
\82 \82È
\82½
\82Í
\8bA
\82Á
\82Ä
\82«
\82½
\82ª
\81C
\8d°
\82ª%s
\82Ü
\82Ü
\82¾
\81D", udeadinside());
681 * The "welcome back" message always describes your innate form
682 * even when polymorphed or wearing a helm of opposite alignment.
683 * Alignment is shown unconditionally for new games; for restores
684 * it's only shown if it has changed from its original value.
685 * Sex is shown for new games except when it is redundant; for
686 * restores it's only shown if different from its original value.
689 if (new_game || u.ualignbase[A_ORIGINAL] != u.ualignbase[A_CURRENT])
691 Sprintf(eos(buf), " %s", align_str(u.ualignbase[A_ORIGINAL]));
693 Sprintf(eos(buf), "%s", align_str(u.ualignbase[A_ORIGINAL]));
696 ? (urole.allow & ROLE_GENDMASK) == (ROLE_MALE | ROLE_FEMALE)
697 : currentgend != flags.initgend))
699 Sprintf(eos(buf), " %s", genders[currentgend].adj);
701 Sprintf(eos(buf), "
\82Ì%s", genders[currentgend].adj);
704 pline(new_game ? "%s %s, welcome to NetHack! You are a%s %s %s."
705 : "%s %s, the%s %s %s, welcome back to NetHack!",
706 Hello((struct monst *) 0), plname, buf, urace.adj,
707 (currentgend && urole.name.f) ? urole.name.f : urole.name.m);
710 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",
711 Hello((struct monst *) 0), urace.adj,
712 (currentgend && urole.name.f) ? urole.name.f : urole.name.m,
715 pline("%s
\81CNetHack
\82Ì
\90¢
\8aE
\82Ö
\81I
\82 \82È
\82½
\82Í%s%s
\82¾
\81I",
716 Hello((struct monst *) 0), urace.adj,
717 (currentgend && urole.name.f) ? urole.name.f : urole.name.m);
726 static char pbar[COLNO];
732 && (glyph_to_cmap(level.locations[upstair.sx][upstair.sy].glyph)
734 || glyph_to_cmap(level.locations[upstair.sx][upstair.sy].glyph)
740 && (glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph)
742 || glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph)
750 && (glyph_to_cmap(level.locations[dnstair.sx][dnstair.sy].glyph)
752 || glyph_to_cmap(level.locations[dnstair.sx][dnstair.sy].glyph)
758 && (glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph)
760 || glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph)
774 update_positionbar(pbar);
782 if (multi > 0 && !context.travel && !context.run) {
784 if (flags.verbose && msg)
790 * Argument processing helpers - for xxmain() to share
793 * These should return TRUE if the argument matched,
794 * whether the processing of the argument was
797 * Most of these do their thing, then after returning
798 * to xxmain(), the code exits without starting a game.
802 static struct early_opt earlyopts[] = {
803 {ARG_DEBUG, "debug", 5, FALSE},
804 {ARG_VERSION, "version", 4, TRUE},
808 argcheck(argc, argv, e_arg)
814 boolean match = FALSE;
815 char *userea = (char *)0;
816 const char *dashdash = "";
818 for (idx = 0; idx < SIZE(earlyopts); idx++) {
819 if (earlyopts[idx].e == e_arg)
822 if ((idx >= SIZE(earlyopts)) || (argc <= 1))
825 for (i = 1; i < argc; ++i) {
826 if (argv[i][0] != '-')
828 if (argv[i][1] == '-') {
829 userea = &argv[i][2];
832 userea = &argv[i][1];
834 match = match_optname(userea, earlyopts[idx].name,
835 earlyopts[idx].minlength, earlyopts[idx].valallowed);
844 boolean insert_into_pastebuf = FALSE;
845 const char *extended_opt = index(userea,':');
848 extended_opt = index(userea, '=');
852 if (match_optname(extended_opt, "paste",
854 insert_into_pastebuf = TRUE;
857 "-%sversion can only be extended with -%sversion:paste.\n",
862 early_version_info(insert_into_pastebuf);