X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=src%2Fend.c;h=6cfdd5aea2141172525087ae968c4bf634df98c1;hb=dad4566636da288ebfe4c1b9214c41a5d6aeabbf;hp=1f223be37e90607afce6227e5be5203c127c3979;hpb=294675b381ab5f81d50c4428f037c38986736202;p=jnethack%2Fsource.git diff --git a/src/end.c b/src/end.c index 1f223be..6cfdd5a 100644 --- a/src/end.c +++ b/src/end.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 end.c $NHDT-Date: 1512803167 2017/12/09 07:06:07 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.137 $ */ +/* NetHack 3.6 end.c $NHDT-Date: 1575245059 2019/12/02 00:04:19 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.181 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -11,7 +11,9 @@ #include #endif #include +#ifndef LONG_MAX #include +#endif #include "dlb.h" /* add b to long a, convert wraparound to max value */ @@ -47,9 +49,9 @@ static void FDECL(done_hangup, (int)); STATIC_DCL void FDECL(disclose, (int, BOOLEAN_P)); STATIC_DCL void FDECL(get_valuables, (struct obj *)); STATIC_DCL void FDECL(sort_valuables, (struct valuable_data *, int)); +STATIC_DCL void NDECL(done_object_cleanup); STATIC_DCL void FDECL(artifact_score, (struct obj *, BOOLEAN_P, winid)); STATIC_DCL void FDECL(really_done, (int)) NORETURN; -STATIC_DCL boolean FDECL(odds_and_ends, (struct obj *, int)); STATIC_DCL void FDECL(savelife, (int)); STATIC_PTR int FDECL(CFDECLSPEC vanqsort_cmp, (const genericptr, const genericptr)); @@ -63,7 +65,7 @@ STATIC_DCL void NDECL(dump_plines); STATIC_DCL void FDECL(dump_everything, (int, time_t)); STATIC_DCL int NDECL(num_extinct); -#if defined(__BEOS__) || defined(MICRO) || defined(WIN32) || defined(OS2) +#if defined(__BEOS__) || defined(MICRO) || defined(OS2) extern void FDECL(nethack_exit, (int)); #else #define nethack_exit exit @@ -127,14 +129,18 @@ static boolean NDECL(NH_panictrace_libc); static boolean NDECL(NH_panictrace_gdb); #ifndef NO_SIGNAL -/*ARGSUSED*/ -void panictrace_handler( - sig_unused) /* called as signal() handler, so sent at least one arg */ +/* called as signal() handler, so sent at least one arg */ +/*ARGUSED*/ +void +panictrace_handler(sig_unused) int sig_unused UNUSED; { #define SIG_MSG "\nSignal received.\n" - (void) write(2, SIG_MSG, sizeof(SIG_MSG) - 1); - NH_abort(); + int f2; + + f2 = (int) write(2, SIG_MSG, sizeof SIG_MSG - 1); + nhUse(f2); /* what could we do if write to fd#2 (stderr) fails */ + NH_abort(); /* ... and we're already in the process of quitting? */ } void @@ -200,7 +206,7 @@ NH_abort() traceback and exit; 2 = show traceback and stay in debugger */ /* if (wizard && gdb_prio == 1) gdb_prio = 2; */ vms_traceback(gdb_prio); - (void) libc_prio; /* half-hearted attempt at lint suppression */ + nhUse(libc_prio); #endif /* ?VMS */ @@ -251,8 +257,8 @@ NH_panictrace_gdb() #ifdef PANICTRACE_GDB /* A (more) generic method to get a stack trace - invoke * gdb on ourself. */ - char *gdbpath = GDBVAR; - char *greppath = GREPVAR; + const char *gdbpath = GDBVAR; + const char *greppath = GREPVAR; char buf[BUFSZ]; FILE *gdb; @@ -261,8 +267,8 @@ NH_panictrace_gdb() if (greppath == NULL || greppath[0] == 0) return FALSE; - sprintf(buf, "%s -n -q %s %d 2>&1 | %s '^#'", gdbpath, ARGV0, getpid(), - greppath); + sprintf(buf, "%s -n -q %s %d 2>&1 | %s '^#'", + gdbpath, ARGV0, getpid(), greppath); gdb = popen(buf, "w"); if (gdb) { raw_print("Generating more information you may report:\n"); @@ -342,6 +348,8 @@ int sig_unused UNUSED; int done2() { + if (iflags.debug_fuzzer) + return 0; /*JP if (!paranoid_query(ParanoidQuit, "Really quit?")) { */ @@ -429,7 +437,7 @@ int how; ? &mons[mtmp->cham] : mptr); boolean distorted = (boolean) (Hallucination && canspotmon(mtmp)), - mimicker = (mtmp->m_ap_type == M_AP_MONSTER), + mimicker = (M_AP_TYPE(mtmp) == M_AP_MONSTER), imitator = (mptr != champtr || mimicker); /*JP @@ -475,7 +483,7 @@ int how; set up fake mptr for type_is_pname/the_unique_pm */ mptr = &mons[mtmp->mappearance]; fakenm = mptr->mname; -#if 0 /*JP*/ +#if 0 /*JP:T*/ } else if (alt && strstri(realnm, "vampire") && !strcmp(fakenm, "vampire bat")) { /* special case: use "vampire in bat form" in preference @@ -503,7 +511,7 @@ int how; Strcpy(shape, fakenm); #endif /* omit "called" to avoid excessive verbosity */ -#if 0 /*JP*/ +#if 0 /*JP:T*/ Sprintf(eos(buf), alt ? "%s in %s form" : mimicker ? "%s disguised as %s" @@ -554,6 +562,15 @@ int how; } Strcpy(killer.name, buf); + /* + * Chicken and egg issue: + * Ordinarily Unchanging ought to override something like this, + * but the transformation occurs at death. With the current code, + * the effectiveness of Unchanging stops first, but a case could + * be made that it should last long enough to prevent undead + * transformation. (Turning to slime isn't an issue here because + * Unchanging prevents that from happening.) + */ if (mptr->mlet == S_WRAITH) u.ugrave_arise = PM_WRAITH; else if (mptr->mlet == S_MUMMY && urace.mummynum != NON_PM) @@ -582,7 +599,6 @@ int how; ‰ö•¨‚É‚æ‚éê‡‚Í "‚ÉŽE‚³‚ꂽ" ‚ð•â‚¤B */ killer.format = KILLED_SUFFIX; - done(DIED); } #endif done(how); @@ -590,6 +606,7 @@ int how; } /* some special cases for overriding while-helpless reason */ +#if 0 /*JP*//*“ú–{Œê‚Å‚ÍŽg‚í‚È‚¢*/ static const struct { int why, unmulti; const char *exclude, *include; @@ -626,6 +643,7 @@ int how; } } } +#endif #if defined(WIN32) && !defined(SYSCF) #define NOTIFY_NETHACK_BUGS @@ -663,15 +681,15 @@ VA_DECL(const char *, str) */ : "“Ë‘R–À‹{‚ª•ö‚ꂽD"); #ifndef MICRO -#if defined(NOTIFY_NETHACK_BUGS) +#ifdef NOTIFY_NETHACK_BUGS if (!wizard) raw_printf("Report the following error to \"%s\" or at \"%s\".", DEVTEAM_EMAIL, DEVTEAM_URL); else if (program_state.something_worth_saving) raw_print("\nError save file being written.\n"); -#else +#else /* !NOTIFY_NETHACK_BUGS */ if (!wizard) { -#if 0 /*JP*/ +#if 0 /*JP:T*/ const char *maybe_rebuild = !program_state.something_worth_saving ? "." : "\nand it may be possible to rebuild."; @@ -688,7 +706,7 @@ VA_DECL(const char *, str) raw_printf("To report this error, contact %s%s", sysopt.fmtd_wizard_list, maybe_rebuild); else -#if 0 /*JP*/ +#if 0 /*JP:T*/ raw_printf("Report error to \"%s\"%s", WIZARD_NAME, maybe_rebuild); #else @@ -696,11 +714,11 @@ VA_DECL(const char *, str) maybe_rebuild); #endif } -#endif +#endif /* ?NOTIFY_NETHACK_BUGS */ /* XXX can we move this above the prints? Then we'd be able to * suppress "it may be possible to rebuild" based on dosave0() * or say it's NOT possible to rebuild. */ - if (program_state.something_worth_saving) { + if (program_state.something_worth_saving && !iflags.debug_fuzzer) { set_error_savefile(); if (dosave0()) { /* os/win port specific recover instructions */ @@ -708,11 +726,15 @@ VA_DECL(const char *, str) raw_printf("%s", sysopt.recover); } } -#endif +#endif /* !MICRO */ { char buf[BUFSZ]; +#if !defined(NO_VSNPRINTF) + (void) vsnprintf(buf, sizeof buf, str, VA_ARGS); +#else Vsprintf(buf, str, VA_ARGS); +#endif raw_print(buf); paniclog("panic", buf); } @@ -780,7 +802,10 @@ dump_plines() extern unsigned saved_pline_index; Strcpy(buf, " "); /* one space for indentation */ +/*JP putstr(0, 0, "Latest messages:"); +*/ + putstr(0, 0, "ÅŒã‚̃ƒbƒZ[ƒW:"); for (i = 0, j = (int) saved_pline_index; i < DUMPLOG_MSG_COUNT; ++i, j = (j + 1) % DUMPLOG_MSG_COUNT) { strp = &saved_plines[j]; @@ -815,17 +840,32 @@ time_t when; /* date+time at end of game */ build date+time or even with an older nethack version, but we only have access to the one it finished under */ putstr(0, 0, getversionstring(pbuf)); +#if 1 /*JP*/ + putstr(0, 0, version_string_j(pbuf)); +#endif putstr(0, 0, ""); /* game start and end date+time to disambiguate version date+time */ Strcpy(datetimebuf, yyyymmddhhmmss(ubirthday)); +#if 0 /*JP:T*/ Sprintf(pbuf, "Game began %4.4s-%2.2s-%2.2s %2.2s:%2.2s:%2.2s", &datetimebuf[0], &datetimebuf[4], &datetimebuf[6], &datetimebuf[8], &datetimebuf[10], &datetimebuf[12]); +#else + Sprintf(pbuf, "ƒQ[ƒ€ŠJŽn %4.4s-%2.2s-%2.2s %2.2s:%2.2s:%2.2s", + &datetimebuf[0], &datetimebuf[4], &datetimebuf[6], + &datetimebuf[8], &datetimebuf[10], &datetimebuf[12]); +#endif Strcpy(datetimebuf, yyyymmddhhmmss(when)); +#if 0 /*JP*/ Sprintf(eos(pbuf), ", ended %4.4s-%2.2s-%2.2s %2.2s:%2.2s:%2.2s.", &datetimebuf[0], &datetimebuf[4], &datetimebuf[6], &datetimebuf[8], &datetimebuf[10], &datetimebuf[12]); +#else + Sprintf(eos(pbuf), ", I—¹ %4.4s-%2.2s-%2.2s %2.2s:%2.2s:%2.2s.", + &datetimebuf[0], &datetimebuf[4], &datetimebuf[6], + &datetimebuf[8], &datetimebuf[10], &datetimebuf[12]); +#endif putstr(0, 0, pbuf); putstr(0, 0, ""); @@ -845,8 +885,11 @@ time_t when; /* date+time at end of game */ dump_plines(); putstr(0, 0, ""); +/*JP putstr(0, 0, "Inventory:"); - display_inventory((char *) 0, TRUE); +*/ + putstr(0, 0, "Ž‚¿•¨:"); + (void) display_inventory((char *) 0, TRUE); container_contents(invent, TRUE, TRUE, FALSE); enlightenment((BASICENLIGHTENMENT | MAGICENLIGHTENMENT), (how >= PANICKED) ? ENL_GAMEOVERALIVE : ENL_GAMEOVERDEAD); @@ -877,7 +920,7 @@ boolean taken; if (invent && !done_stopprint) { if (taken) -#if 0 /*JP*/ +#if 0 /*JP:T*/ Sprintf(qbuf, "Do you want to see what you had when you %s?", (how == QUIT) ? "quit" : "died"); #else @@ -903,7 +946,7 @@ boolean taken; if (!done_stopprint) { ask = should_query_disclose_option('a', &defquery); -#if 0 /*JP*/ +#if 0 /*JP:T*/ c = ask ? yn_function("Do you want to see your attributes?", ynqchars, defquery) : defquery; @@ -932,7 +975,7 @@ boolean taken; if (!done_stopprint) { ask = should_query_disclose_option('c', &defquery); -#if 0 /*JP*/ +#if 0 /*JP:T*/ c = ask ? yn_function("Do you want to see your conduct?", ynqchars, defquery) : defquery; @@ -949,7 +992,7 @@ boolean taken; if (!done_stopprint) { ask = should_query_disclose_option('o', &defquery); -#if 0 /*JP*/ +#if 0 /*JP:T*/ c = ask ? yn_function("Do you want to see the dungeon overview?", ynqchars, defquery) : defquery; @@ -975,18 +1018,15 @@ int how; if (u.uhpmax < uhpmin) u.uhpmax = uhpmin; u.uhp = u.uhpmax; - u.uswldtim = 0; - if (u.uhunger < 500) { - u.uhunger = 500; - newuhs(FALSE); + if (Upolyd) /* Unchanging, or death which bypasses losing hit points */ + u.mh = u.mhmax; + if (u.uhunger < 500 || how == CHOKING) { + init_uhunger(); } /* cure impending doom of sickness hero won't have time to fix */ if ((Sick & TIMEOUT) == 1L) { - u.usick_type = 0; - set_itimeout(&Sick, 0L); + make_sick(0L, (char *) 0, FALSE, SICK_ALL); } - if (how == CHOKING) - init_uhunger(); /*JP nomovemsg = "You survived that attempt on your life."; */ @@ -997,13 +1037,23 @@ int how; else multi = -1; if (u.utrap && u.utraptype == TT_LAVA) - u.utrap = 0; + reset_utrap(FALSE); context.botl = 1; u.ugrave_arise = NON_PM; HUnchanging = 0L; curs_on_u(); if (!context.mon_moving) endmultishot(FALSE); + if (u.uswallow) { + /* might drop hero onto a trap that kills her all over again */ + expels(u.ustuck, u.ustuck->data, TRUE); + } else if (u.ustuck) { + if (Upolyd && sticks(youmonst.data)) + You("release %s.", mon_nam(u.ustuck)); + else + pline("%s releases you.", Monnam(u.ustuck)); + unstuck(u.ustuck); + } } /* @@ -1069,6 +1119,13 @@ int size; /* max value is less than 20 */ return; } +#if 0 +/* + * odds_and_ends() was used for 3.6.0 and 3.6.1. + * Schroedinger's Cat is handled differently as of 3.6.2. + */ +STATIC_DCL boolean FDECL(odds_and_ends, (struct obj *, int)); + #define CAT_CHECK 2 STATIC_OVL boolean @@ -1077,6 +1134,7 @@ struct obj *list; int what; { struct obj *otmp; + for (otmp = list; otmp; otmp = otmp->nobj) { switch (what) { case CAT_CHECK: /* Schroedinger's Cat */ @@ -1090,6 +1148,63 @@ int what; } return FALSE; } +#endif + +/* deal with some objects which may be in an abnormal state at end of game */ +STATIC_OVL void +done_object_cleanup() +{ + int ox, oy; + + /* might have been killed while using a disposable item, so make sure + it's gone prior to inventory disclosure and creation of bones */ + inven_inuse(TRUE); + /* + * Hero can die when throwing an object (by hitting an adjacent + * gas spore, for instance, or being hit by mis-returning Mjollnir), + * or while in transit (from falling down stairs). If that happens, + * some object(s) might be in limbo rather than on the map or in + * any inventory. Saving bones with an active light source in limbo + * would trigger an 'object not local' panic. + * + * We used to use dealloc_obj() on thrownobj and kickedobj but + * that keeps them out of bones and could leave uball in a confused + * state (gone but still attached). Place them on the map but + * bypass flooreffects(). That could lead to minor anomalies in + * bones, like undamaged paper at water or lava locations or piles + * not being knocked down holes, but it seems better to get this + * game over with than risk being tangled up in more and more details. + */ + ox = u.ux + u.dx, oy = u.uy + u.dy; + if (!isok(ox, oy) || !accessible(ox, oy)) + ox = u.ux, oy = u.uy; + /* put thrown or kicked object on map (for bones); location might + be incorrect (perhaps killed by divine lightning when throwing at + a temple priest?) but this should be better than just vanishing + (fragile stuff should be taken care of before getting here) */ + if (thrownobj && thrownobj->where == OBJ_FREE) { + place_object(thrownobj, ox, oy); + stackobj(thrownobj), thrownobj = 0; + } + if (kickedobj && kickedobj->where == OBJ_FREE) { + place_object(kickedobj, ox, oy); + stackobj(kickedobj), kickedobj = 0; + } + /* if Punished hero dies during level change or dies or quits while + swallowed, uball and uchain will be in limbo; put them on floor + so bones will have them and object list cleanup finds them */ + if (uchain && uchain->where == OBJ_FREE) { + /* placebc(); */ + lift_covet_and_placebc(override_restriction); + } + /* persistent inventory window now obsolete since disclosure uses + a normal popup one; avoids "Bad fruit #n" when saving bones */ + if (iflags.perm_invent) { + iflags.perm_invent = FALSE; + update_inventory(); /* make interface notice the change */ + } + return; +} /* called twice; first to calculate total, then to list relevant items */ STATIC_OVL void @@ -1112,10 +1227,10 @@ winid endwin; if (counting) { nowrap_add(u.urexp, points); } else { - makeknown(otmp->otyp); + discover_object(otmp->otyp, TRUE, FALSE); otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1; /* assumes artifacts don't have quan > 1 */ -#if 0 /*JP*/ +#if 0 /*JP:T*/ Sprintf(pbuf, "%s%s (worth %ld %s and %ld points)", the_unique_obj(otmp) ? "The " : "", otmp->oartifact ? artifact_name(xname(otmp), &dummy) @@ -1140,16 +1255,19 @@ void done(how) int how; { + boolean survive = FALSE; + if (how == TRICKED) { if (killer.name[0]) { paniclog("trickery", killer.name); - killer.name[0] = 0; + killer.name[0] = '\0'; } if (wizard) { /*JP You("are a very tricky wizard, it seems."); */ You("‚Æ‚Ä‚àˆµ‚¢‚É‚­‚¢wizard‚̂悤‚¾D"); + killer.format = KILLED_BY_AN; /* reset to 0 */ return; } } @@ -1159,13 +1277,33 @@ int how; #endif ) { /* skip status update if panicking or disconnected */ - context.botl = context.botlx = FALSE; + context.botl = context.botlx = iflags.time_botl = FALSE; } else { /* otherwise force full status update */ context.botlx = TRUE; bot(); } + if (iflags.debug_fuzzer) { + if (!(program_state.panicking || how == PANICKED)) { + savelife(how); + /* periodically restore characteristics and lost exp levels + or cure lycanthropy */ + if (!rn2(10)) { + struct obj *potion = mksobj((u.ulycn > LOW_PM && !rn2(3)) + ? POT_WATER : POT_RESTORE_ABILITY, + TRUE, FALSE); + + bless(potion); + (void) peffects(potion); /* always -1 for restore ability */ + /* not useup(); we haven't put this potion into inventory */ + obfree(potion, (struct obj *) 0); + } + killer.name[0] = '\0'; + killer.format = 0; + return; + } + } else if (how == ASCENDED || (!killer.name[0] && how == GENOCIDED)) killer.format = NO_KILLER_PREFIX; /* Avoid killed by "a" burning or "a" starvation */ @@ -1177,8 +1315,18 @@ int how; */ Strcpy(killer.name, ends[how]); - if (how < PANICKED) + if (how < PANICKED) { u.umortality++; + /* in case caller hasn't already done this */ + if (u.uhp != 0 || (Upolyd && u.mh != 0)) { + /* force HP to zero in case it is still positive (some + deaths aren't triggered by loss of hit points), or + negative (-1 is used as a flag in some circumstances + which don't apply when actually dying due to HP loss) */ + u.uhp = u.mh = 0; + context.botl = 1; + } + } if (Lifesaved && (how <= GENOCIDED)) { /*JP pline("But wait..."); @@ -1213,28 +1361,33 @@ int how; */ pline("Žc”O‚È‚ª‚çC‚ ‚È‚½‚Í‹sŽE‚³‚ꂽ‚Ü‚Ü‚¾DDD"); } else { - killer.name[0] = 0; - killer.format = 0; - return; + survive = TRUE; } } -#if 0 /*JP*/ - if ((wizard || discover) && (how <= GENOCIDED) + /* explore and wizard modes offer player the option to keep playing */ +#if 0 /*JP:T*/ + if (!survive && (wizard || discover) && how <= GENOCIDED && !paranoid_query(ParanoidDie, "Die?")) { #else - if ((wizard || discover) && (how <= GENOCIDED) + if (!survive && (wizard || discover) && how <= GENOCIDED && !paranoid_query(ParanoidDie, "Ž€‚ñ‚Å‚Ý‚éH")) { #endif /*JP pline("OK, so you don't %s.", (how == CHOKING) ? "choke" : "die"); */ You("Ž€‚È‚È‚©‚Á‚½D"); + iflags.last_msg = PLNMSG_OK_DONT_DIE; savelife(how); - killer.name[0] = 0; - killer.format = 0; + survive = TRUE; + } + + if (survive) { + killer.name[0] = '\0'; + killer.format = KILLED_BY_AN; /* reset to 0 */ return; } really_done(how); + /*NOTREACHED*/ } /* separated from done() in order to specify the __noreturn__ attribute */ @@ -1257,33 +1410,37 @@ int how; program_state.gameover = 1; /* in case of a subsequent panic(), there's no point trying to save */ program_state.something_worth_saving = 0; +#ifdef HANGUPHANDLING + if (program_state.done_hup) + done_stopprint++; +#endif /* render vision subsystem inoperative */ iflags.vision_inited = 0; - /* might have been killed while using a disposable item, so make sure - it's gone prior to inventory disclosure and creation of bones data */ - inven_inuse(TRUE); - /* maybe not on object lists; if an active light source, would cause - big trouble (`obj_is_local' panic) for savebones() -> savelev() */ - if (thrownobj && thrownobj->where == OBJ_FREE) - dealloc_obj(thrownobj); - if (kickedobj && kickedobj->where == OBJ_FREE) - dealloc_obj(kickedobj); + /* maybe use up active invent item(s), place thrown/kicked missile, + deal with ball and chain possibly being temporarily off the map */ + if (!program_state.panicking) + done_object_cleanup(); + /* in case we're panicking; normally cleared by done_object_cleanup() */ + iflags.perm_invent = FALSE; /* remember time of death here instead of having bones, rip, and topten figure it out separately and possibly getting different time or even day if player is slow responding to --More-- */ urealtime.finish_time = endtime = getnow(); urealtime.realtime += (long) (endtime - urealtime.start_timing); + /* collect these for end of game disclosure (not used during play) */ + iflags.at_night = night(); + iflags.at_midnight = midnight(); dump_open_log(endtime); /* Sometimes you die on the first move. Life's not fair. * On those rare occasions you get hosed immediately, go out * smiling... :-) -3. */ - if (moves <= 1 && how < PANICKED) /* You die... --More-- */ + if (moves <= 1 && how < PANICKED && !done_stopprint) /*JP - pline("Do not pass go. Do not collect 200 %s.", currency(200L)); + pline("Do not pass Go. Do not collect 200 %s.", currency(200L)); */ pline("’ˆÓˆê•bC‰ö‰äˆê¶CŽ€–Sˆê•àD"); @@ -1309,7 +1466,12 @@ int how; u.ugrave_arise = (NON_PM - 2); /* leave no corpse */ else if (how == STONING) u.ugrave_arise = (NON_PM - 1); /* statue instead of corpse */ - else if (how == TURNED_SLIME) + else if (how == TURNED_SLIME + /* it's possible to turn into slime even though green slimes + have been genocided: genocide could occur after hero is + already infected or hero could eat a glob of one created + before genocide; don't try to arise as one if they're gone */ + && !(mvitals[PM_GREEN_SLIME].mvflags & G_GENOD)) u.ugrave_arise = PM_GREEN_SLIME; if (how == QUIT) { @@ -1326,12 +1488,16 @@ int how; if (how == ESCAPED || how == PANICKED) killer.format = NO_KILLER_PREFIX; +#if 0 /*JP*//*“ú–{Œê‚Å‚ÍŽg‚í‚È‚¢*/ fixup_death(how); /* actually, fixup multi_reason */ +#endif if (how != PANICKED) { + boolean silently = done_stopprint ? TRUE : FALSE; + /* these affect score and/or bones, but avoid them during panic */ - taken = paybill((how == ESCAPED) ? -1 : (how != QUIT)); - paygd(); + taken = paybill((how == ESCAPED) ? -1 : (how != QUIT), silently); + paygd(silently); clearpriests(); } else taken = FALSE; /* lint; assert( !bones_ok ); */ @@ -1350,10 +1516,24 @@ int how; * it in both of those places. */ for (obj = invent; obj; obj = obj->nobj) { - makeknown(obj->otyp); + discover_object(obj->otyp, TRUE, FALSE); obj->known = obj->bknown = obj->dknown = obj->rknown = 1; if (Is_container(obj) || obj->otyp == STATUE) obj->cknown = obj->lknown = 1; + /* we resolve Schroedinger's cat now in case of both + disclosure and dumplog, where the 50:50 chance for + live cat has to be the same both times */ + if (SchroedingersBox(obj)) { + if (!Schroedingers_cat) { + /* tell observe_quantum_cat() not to create a cat; if it + chooses live cat in this situation, it will leave the + SchroedingersBox flag set (for container_contents()) */ + observe_quantum_cat(obj, FALSE, FALSE); + if (SchroedingersBox(obj)) + Schroedingers_cat = TRUE; + } else + obj->spe = 0; /* ordinary box with cat corpse in it */ + } } if (strcmp(flags.end_disclose, "none")) @@ -1364,7 +1544,7 @@ int how; /* if pets will contribute to score, populate mydogs list now (bones creation isn't a factor, but pline() messaging is; used to - be done ever sooner, but we need it to come after dump_everything() + be done even sooner, but we need it to come after dump_everything() so that any accompanying pets are still on the map during dump) */ if (how == ESCAPED || how == ASCENDED) keepdogs(TRUE); @@ -1380,10 +1560,8 @@ int how; int mnum = u.umonnum; if (!Upolyd) { - /* Base corpse on race when not poly'd since original - * u.umonnum is based on role, and all role monsters - * are human. - */ + /* Base corpse on race when not poly'd since original u.umonnum + is based on role, and all role monsters are human. */ mnum = (flags.female && urace.femalenum != NON_PM) ? urace.femalenum : urace.malenum; @@ -1427,15 +1605,23 @@ int how; } } - if (u.ugrave_arise >= LOW_PM && u.ugrave_arise != PM_GREEN_SLIME) { + if (u.ugrave_arise >= LOW_PM && !done_stopprint) { /* give this feedback even if bones aren't going to be created, so that its presence or absence doesn't tip off the player to new bones or their lack; it might be a lie if makemon fails */ -/*JP - Your("body rises from the dead as %s...", -*/ - Your("‘Ì‚Í%s‚Æ‚µ‚ÄŽ€‘Ì‚©‚ç‘h‚Á‚½DDD", +#if 0 /*JP:T*/ + Your("%s as %s...", + (u.ugrave_arise != PM_GREEN_SLIME) + ? "body rises from the dead" + : "revenant persists", an(mons[u.ugrave_arise].mname)); +#else + Your("%s as %s‚É‚È‚Á‚½DDD", + (u.ugrave_arise != PM_GREEN_SLIME) + ? "‘Ì‚ÍŽ€‘Ì‚©‚ç‘h‚Á‚Ä" + : "–S—ì‚Í", + mons[u.ugrave_arise].mname); +#endif display_nhwindow(WIN_MESSAGE, FALSE); } @@ -1461,13 +1647,12 @@ int how; if (WIN_INVEN != WIN_ERR) { destroy_nhwindow(WIN_INVEN), WIN_INVEN = WIN_ERR; /* precaution in case any late update_inventory() calls occur */ - flags.perm_invent = 0; + iflags.perm_invent = 0; } display_nhwindow(WIN_MESSAGE, TRUE); destroy_nhwindow(WIN_MAP), WIN_MAP = WIN_ERR; -#ifndef STATUS_HILITES - destroy_nhwindow(WIN_STATUS), WIN_STATUS = WIN_ERR; -#endif + if (WIN_STATUS != WIN_ERR) + destroy_nhwindow(WIN_STATUS), WIN_STATUS = WIN_ERR; destroy_nhwindow(WIN_MESSAGE), WIN_MESSAGE = WIN_ERR; if (!done_stopprint || flags.tombstone) @@ -1507,7 +1692,7 @@ int how; /* don't bother counting to see whether it should be plural */ } -#if 0 /*JP*/ +#if 0 /*JP:T*/ Sprintf(pbuf, "%s %s the %s...", Goodbye(), plname, (how != ASCENDED) ? (const char *) ((flags.female && urole.name.f) @@ -1553,31 +1738,31 @@ int how; viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */ mtmp = mydogs; /*JP - Strcpy(pbuf, "You"); + Strcpy(pbuf, "You"); */ - Strcpy(pbuf, "‚ ‚È‚½"); - if (!Schroedingers_cat) /* check here in case disclosure was off */ - Schroedingers_cat = odds_and_ends(invent, CAT_CHECK); - if (Schroedingers_cat) { - int mhp, m_lev = adj_lev(&mons[PM_HOUSECAT]); - - mhp = d(m_lev, 8); - nowrap_add(u.urexp, mhp); -/*JP - Strcat(eos(pbuf), " and Schroedinger's cat"); -*/ - Strcat(eos(pbuf), "‚ƃVƒ…ƒŒƒfƒBƒ“ƒK[‚Ì”L"); - } - if (mtmp) { + Strcpy(pbuf, "‚ ‚È‚½"); + if (mtmp || Schroedingers_cat) { while (mtmp) { /*JP - Sprintf(eos(pbuf), " and %s", mon_nam(mtmp)); + Sprintf(eos(pbuf), " and %s", mon_nam(mtmp)); */ - Sprintf(eos(pbuf), "‚Æ%s", mon_nam(mtmp)); + Sprintf(eos(pbuf), "‚Æ%s", mon_nam(mtmp)); if (mtmp->mtame) nowrap_add(u.urexp, mtmp->mhp); mtmp = mtmp->nmon; } + /* [it might be more robust to create a housecat and add it to + mydogs; it doesn't have to be placed on the map for that] */ + if (Schroedingers_cat) { + int mhp, m_lev = adj_lev(&mons[PM_HOUSECAT]); + + mhp = d(m_lev, 8); + nowrap_add(u.urexp, mhp); +/*JP + Strcat(eos(pbuf), " and Schroedinger's cat"); +*/ + Strcat(eos(pbuf), "‚ƃVƒ…ƒŒƒfƒBƒ“ƒK[‚Ì”L"); + } #if 1 /*JP*/ if (!done_stopprint) Strcat(pbuf, "‚Í"); @@ -1586,11 +1771,11 @@ int how; pbuf[0] = '\0'; } else { /*JP - Strcat(pbuf, " "); + Strcat(pbuf, " "); */ - Strcat(pbuf, "‚Í"); + Strcat(pbuf, "‚Í"); } -#if 0 /*JP*/ +#if 0 /*JP:T*/ Sprintf(eos(pbuf), "%s with %ld point%s,", how == ASCENDED ? "went to your reward" : "escaped from the dungeon", @@ -1622,13 +1807,13 @@ int how; continue; if (objects[typ].oc_class != GEM_CLASS || typ <= LAST_GEM) { otmp = mksobj(typ, FALSE, FALSE); - makeknown(otmp->otyp); + discover_object(otmp->otyp, TRUE, FALSE); otmp->known = 1; /* for fake amulets */ otmp->dknown = 1; /* seen it (blindness fix) */ if (has_oname(otmp)) free_oname(otmp); otmp->quan = count; -#if 0 /*JP*/ +#if 0 /*JP:T*/ Sprintf(pbuf, "%8ld %s (worth %ld %s),", count, xname(otmp), count * (long) objects[typ].oc_cost, currency(2L)); @@ -1639,7 +1824,7 @@ int how; #endif obfree(otmp, (struct obj *) 0); } else { -#if 0 /*JP*/ +#if 0 /*JP:T*/ Sprintf(pbuf, "%8ld worthless piece%s of colored glass,", count, plur(count)); #else @@ -1656,7 +1841,7 @@ int how; if (u.uz.dnum == 0 && u.uz.dlevel <= 0) { /* level teleported out of the dungeon; `how' is DIED, due to falling or to "arriving at heaven prematurely" */ -#if 0 /*JP*/ +#if 0 /*JP:T*/ Sprintf(pbuf, "You %s beyond the confines of the dungeon", (u.uz.dlevel < 0) ? "passed away" : ends[how]); #else @@ -1677,7 +1862,7 @@ int how; */ Sprintf(pbuf, "‚ ‚È‚½‚Í%s", where); if (!In_endgame(&u.uz) && !Is_knox(&u.uz)) -#if 0 /*JP*/ +#if 0 /*JP:T*/ Sprintf(eos(pbuf), " on dungeon level %d", In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz)); #else @@ -1740,73 +1925,72 @@ boolean identified, all_containers, reportempty; { register struct obj *box, *obj; char buf[BUFSZ]; - boolean cat, deadcat; + boolean cat, dumping = iflags.in_dumplog; for (box = list; box; box = box->nobj) { if (Is_container(box) || box->otyp == STATUE) { - box->cknown = 1; /* we're looking at the contents now */ - if (identified) - box->lknown = 1; - cat = deadcat = FALSE; - if (SchroedingersBox(box) && !Schroedingers_cat) { - /* Schroedinger's Cat? */ - cat = odds_and_ends(box, CAT_CHECK); - if (cat) - Schroedingers_cat = TRUE; - else - deadcat = TRUE; - box->spe = 0; + if (!box->cknown || (identified && !box->lknown)) { + box->cknown = 1; /* we're looking at the contents now */ + if (identified) + box->lknown = 1; + update_inventory(); } if (box->otyp == BAG_OF_TRICKS) { continue; /* wrong type of container */ } else if (box->cobj) { winid tmpwin = create_nhwindow(NHW_MENU); + Loot *sortedcobj, *srtc; + unsigned sortflags; + + /* at this stage, the SchroedingerBox() flag is only set + if the cat inside the box is alive; the box actually + contains a cat corpse that we'll pretend is not there; + for dead cat, the flag will be clear and there'll be + a cat corpse inside the box; either way, inventory + reports the box as containing "1 item" */ + cat = SchroedingersBox(box); - sortloot(&box->cobj, - (((flags.sortloot == 'l' || flags.sortloot == 'f') - ? SORTLOOT_LOOT : 0) - | (flags.sortpack ? SORTLOOT_PACK : 0)), - FALSE); /*JP Sprintf(buf, "Contents of %s:", the(xname(box))); */ Sprintf(buf, "%s‚Ì’†gF", the(xname(box))); putstr(tmpwin, 0, buf); - putstr(tmpwin, 0, ""); - for (obj = box->cobj; obj; obj = obj->nobj) { - if (identified) { - makeknown(obj->otyp); - obj->known = obj->bknown = obj->dknown - = obj->rknown = 1; - if (Is_container(obj) || obj->otyp == STATUE) - obj->cknown = obj->lknown = 1; + if (!dumping) + putstr(tmpwin, 0, ""); + buf[0] = buf[1] = ' '; /* two leading spaces */ + if (box->cobj && !cat) { + sortflags = (((flags.sortloot == 'l' + || flags.sortloot == 'f') + ? SORTLOOT_LOOT : 0) + | (flags.sortpack ? SORTLOOT_PACK : 0)); + sortedcobj = sortloot(&box->cobj, sortflags, FALSE, + (boolean FDECL((*), (OBJ_P))) 0); + for (srtc = sortedcobj; ((obj = srtc->obj) != 0); ++srtc) { + if (identified) { + discover_object(obj->otyp, TRUE, FALSE); + obj->known = obj->bknown = obj->dknown + = obj->rknown = 1; + if (Is_container(obj) || obj->otyp == STATUE) + obj->cknown = obj->lknown = 1; + } + Strcpy(&buf[2], doname_with_price(obj)); + putstr(tmpwin, 0, buf); } - putstr(tmpwin, 0, doname(obj)); - } - if (cat) + unsortloot(&sortedcobj); + } else if (cat) { /*JP - putstr(tmpwin, 0, "Schroedinger's cat"); + Strcpy(&buf[2], "Schroedinger's cat!"); */ - putstr(tmpwin, 0, "ƒVƒ…ƒŒƒfƒBƒ“ƒK[‚Ì”L"); - else if (deadcat) -/*JP - putstr(tmpwin, 0, "Schroedinger's dead cat"); -*/ - putstr(tmpwin, 0, "ƒVƒ…ƒŒƒfƒBƒ“ƒK[‚Ì”L‚ÌŽ€‘Ì"); + Strcpy(&buf[2], "ƒVƒ…ƒŒƒfƒBƒ“ƒK[‚Ì”LI"); + putstr(tmpwin, 0, buf); + } + if (dumping) + putstr(0, 0, ""); display_nhwindow(tmpwin, TRUE); destroy_nhwindow(tmpwin); if (all_containers) container_contents(box->cobj, identified, TRUE, reportempty); - } else if (cat || deadcat) { -#if 0 /*JP*/ - pline("%s Schroedinger's %scat!", Tobjnam(box, "contain"), - deadcat ? "dead " : ""); -#else - pline("%s‚ɂ̓Vƒ…ƒŒƒfƒBƒ“ƒK[‚Ì”L%s‚ª“ü‚Á‚Ä‚¢‚½I", xname(box), - deadcat ? "‚ÌŽ€‘Ì" : ""); -#endif - display_nhwindow(WIN_MESSAGE, FALSE); } else if (reportempty) { /*JP pline("%s is empty.", upstart(thesimpleoname(box))); @@ -1854,8 +2038,6 @@ int status; nethack_exit(status); } -extern const int monstr[]; - enum vanq_order_modes { VANQ_MLVL_MNDX = 0, VANQ_MSTR_MNDX, @@ -1900,7 +2082,7 @@ const genericptr vptr2; break; case VANQ_MSTR_MNDX: /* sort by monster toughness */ - mstr1 = monstr[indx1], mstr2 = monstr[indx2]; + mstr1 = mons[indx1].difficulty, mstr2 = mons[indx2].difficulty; res = mstr2 - mstr1; /* monstr high to low */ break; case VANQ_ALPHA_SEP: @@ -1980,7 +2162,10 @@ set_vanq_order() add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, vanqorders[i], (i == vanq_sortmode) ? MENU_SELECTED : MENU_UNSELECTED); } +/*JP end_menu(tmpwin, "Sort order for vanquished monster counts"); +*/ + end_menu(tmpwin, "“|‚µ‚½“G‚̃\[ƒg‡"); n = select_menu(tmpwin, PICK_ONE, &selected); destroy_nhwindow(tmpwin); @@ -2093,7 +2278,7 @@ boolean ask; Sprintf(buf, "%s", mons[i].mname); #endif if (nkilled > 1) { -#if 0 /*JP*/ +#if 0 /*JP:T*/ switch (nkilled) { case 2: Sprintf(eos(buf), " (twice)"); @@ -2129,10 +2314,14 @@ boolean ask; #endif } /* number of leading spaces to match 3 digit prefix */ +#if 0 /*JP*/ pfx = !strncmpi(buf, "the ", 3) ? 0 : !strncmpi(buf, "an ", 3) ? 1 : !strncmpi(buf, "a ", 2) ? 2 : !digit(buf[2]) ? 4 : 0; +#else + pfx = !digit(buf[2]) ? 4 : 0; +#endif if (class_header) ++pfx; Sprintf(buftoo, "%*s%s", pfx, "", buf); @@ -2162,7 +2351,11 @@ boolean ask; pline("“|‚µ‚½“G‚Í‚¢‚È‚©‚Á‚½D"); #ifdef DUMPLOG } else if (dumping) { +#if 0 /*JP:T*/ putstr(0, 0, "No creatures were vanquished."); /* not pline() */ +#else + putstr(0, 0, "“|‚µ‚½“G‚Í‚¢‚È‚©‚Á‚½D"); /* not pline() */ +#endif #endif } } @@ -2235,7 +2428,7 @@ boolean ask; done_stopprint++; if (c == 'y') { klwin = create_nhwindow(NHW_MENU); -#if 0 /*JP*/ +#if 0 /*JP:T*/ Sprintf(buf, "%s%s species:", (ngenocided) ? "Genocided" : "Extinct", (nextinct && ngenocided) ? " or extinct" : ""); @@ -2291,7 +2484,10 @@ boolean ask; } #ifdef DUMPLOG } else if (dumping) { +/*JP putstr(0, 0, "No species were genocided or became extinct."); +*/ + putstr(0, 0, "‹sŽE‚µ‚½‚èâ–Å‚³‚¹‚½‚肵‚½Ží‚Í‚¢‚È‚©‚Á‚½D"); #endif } } @@ -2305,10 +2501,10 @@ const char *killername; { struct kinfo *k = find_delayed_killer(id); - if (k == (struct kinfo *) 0) { + if (!k) { /* no match, add a new delayed killer to the list */ - k = (struct kinfo *) alloc(sizeof(struct kinfo)); - (void) memset((genericptr_t)k, 0, sizeof(struct kinfo)); + k = (struct kinfo *) alloc(sizeof (struct kinfo)); + (void) memset((genericptr_t) k, 0, sizeof (struct kinfo)); k->id = id; k->next = killer.next; killer.next = k; @@ -2347,10 +2543,11 @@ struct kinfo *kptr; } if (k == (struct kinfo *) 0) { - impossible("dealloc_killer not on list"); + impossible("dealloc_killer (#%d) not on list", kptr->id); } else { prev->next = k->next; free((genericptr_t) k); + debugpline1("freed delayed killer #%d", kptr->id); } } @@ -2363,7 +2560,7 @@ int mode; if (perform_bwrite(mode)) { for (kptr = &killer; kptr != (struct kinfo *) 0; kptr = kptr->next) { - bwrite(fd, (genericptr_t) kptr, sizeof(struct kinfo)); + bwrite(fd, (genericptr_t) kptr, sizeof (struct kinfo)); } } if (release_data(mode)) { @@ -2382,9 +2579,9 @@ int fd; struct kinfo *kptr; for (kptr = &killer; kptr != (struct kinfo *) 0; kptr = kptr->next) { - mread(fd, (genericptr_t) kptr, sizeof(struct kinfo)); + mread(fd, (genericptr_t) kptr, sizeof (struct kinfo)); if (kptr->next) { - kptr->next = (struct kinfo *) alloc(sizeof(struct kinfo)); + kptr->next = (struct kinfo *) alloc(sizeof (struct kinfo)); } } } @@ -2421,6 +2618,7 @@ char **inp, *out; *inp = in; } +/*JP: files.c‚Å1ƒ–ŠŽg‚í‚ê‚Ä‚¢‚邪‚±‚±‚͉pŒê‚Ì‚Ü‚Ü‚É‚µ‚Ä‚¨‚­*/ char * build_english_list(in) char *in;