-/* 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. */
#include <signal.h>
#endif
#include <ctype.h>
+#ifndef LONG_MAX
#include <limits.h>
+#endif
#include "dlb.h"
/* add b to long a, convert wraparound to max value */
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));
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
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
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 */
#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;
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");
int
done2()
{
+ if (iflags.debug_fuzzer)
+ return 0;
/*JP
if (!paranoid_query(ParanoidQuit, "Really quit?")) {
*/
? &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
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
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"
}
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)
\89ö\95¨\82É\82æ\82é\8fê\8d\87\82Í "\82É\8eE\82³\82ê\82½" \82ð\95â\82¤\81B
*/
killer.format = KILLED_SUFFIX;
- done(DIED);
}
#endif
done(how);
}
/* some special cases for overriding while-helpless reason */
+#if 0 /*JP*//*\93ú\96{\8cê\82Å\82Í\8eg\82í\82È\82¢*/
static const struct {
int why, unmulti;
const char *exclude, *include;
}
}
}
+#endif
#if defined(WIN32) && !defined(SYSCF)
#define NOTIFY_NETHACK_BUGS
*/
: "\93Ë\91R\96À\8b{\82ª\95ö\82ê\82½\81D");
#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.";
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
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 */
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);
}
extern unsigned saved_pline_index;
Strcpy(buf, " "); /* one space for indentation */
+/*JP
putstr(0, 0, "Latest messages:");
+*/
+ putstr(0, 0, "\8dÅ\8cã\82Ì\83\81\83b\83Z\81[\83W:");
for (i = 0, j = (int) saved_pline_index; i < DUMPLOG_MSG_COUNT;
++i, j = (j + 1) % DUMPLOG_MSG_COUNT) {
strp = &saved_plines[j];
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, "\83Q\81[\83\80\8aJ\8en %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), ", \8fI\97¹ %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, "");
dump_plines();
putstr(0, 0, "");
+/*JP
putstr(0, 0, "Inventory:");
- display_inventory((char *) 0, TRUE);
+*/
+ putstr(0, 0, "\8e\9d\82¿\95¨:");
+ (void) display_inventory((char *) 0, TRUE);
container_contents(invent, TRUE, TRUE, FALSE);
enlightenment((BASICENLIGHTENMENT | MAGICENLIGHTENMENT),
(how >= PANICKED) ? ENL_GAMEOVERALIVE : ENL_GAMEOVERDEAD);
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
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;
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;
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;
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.";
*/
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);
+ }
}
/*
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
int what;
{
struct obj *otmp;
+
for (otmp = list; otmp; otmp = otmp->nobj) {
switch (what) {
case CAT_CHECK: /* Schroedinger's Cat */
}
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
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)
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("\82Æ\82Ä\82à\88µ\82¢\82É\82\82¢wizard\82Ì\82æ\82¤\82¾\81D");
+ killer.format = KILLED_BY_AN; /* reset to 0 */
return;
}
}
#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 */
*/
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...");
*/
pline("\8ec\94O\82È\82ª\82ç\81C\82 \82È\82½\82Í\8bs\8eE\82³\82ê\82½\82Ü\82Ü\82¾\81D\81D\81D");
} 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, "\8e\80\82ñ\82Å\82Ý\82é\81H")) {
#endif
/*JP
pline("OK, so you don't %s.", (how == CHOKING) ? "choke" : "die");
*/
You("\8e\80\82È\82È\82©\82Á\82½\81D");
+ 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 */
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("\92\8d\88Ó\88ê\95b\81C\89ö\89ä\88ê\90¶\81C\8e\80\96S\88ê\95à\81D");
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) {
if (how == ESCAPED || how == PANICKED)
killer.format = NO_KILLER_PREFIX;
+#if 0 /*JP*//*\93ú\96{\8cê\82Å\82Í\8eg\82í\82È\82¢*/
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 ); */
* 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"))
/* 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);
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;
}
}
- 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("\91Ì\82Í%s\82Æ\82µ\82Ä\8e\80\91Ì\82©\82ç\91h\82Á\82½\81D\81D\81D",
+#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\82É\82È\82Á\82½\81D\81D\81D",
+ (u.ugrave_arise != PM_GREEN_SLIME)
+ ? "\91Ì\82Í\8e\80\91Ì\82©\82ç\91h\82Á\82Ä"
+ : "\96S\97ì\82Í",
+ mons[u.ugrave_arise].mname);
+#endif
display_nhwindow(WIN_MESSAGE, FALSE);
}
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)
/* 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)
viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */
mtmp = mydogs;
/*JP
- Strcpy(pbuf, "You");
+ Strcpy(pbuf, "You");
*/
- Strcpy(pbuf, "\82 \82È\82½");
- 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), "\82Æ\83V\83\85\83\8c\83f\83B\83\93\83K\81[\82Ì\94L");
- }
- if (mtmp) {
+ Strcpy(pbuf, "\82 \82È\82½");
+ 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), "\82Æ%s", mon_nam(mtmp));
+ Sprintf(eos(pbuf), "\82Æ%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), "\82Æ\83V\83\85\83\8c\83f\83B\83\93\83K\81[\82Ì\94L");
+ }
#if 1 /*JP*/
if (!done_stopprint)
Strcat(pbuf, "\82Í");
pbuf[0] = '\0';
} else {
/*JP
- Strcat(pbuf, " ");
+ Strcat(pbuf, " ");
*/
- Strcat(pbuf, "\82Í");
+ Strcat(pbuf, "\82Í");
}
-#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",
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));
#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
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
*/
Sprintf(pbuf, "\82 \82È\82½\82Í%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
{
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\82Ì\92\86\90g\81F", 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, "\83V\83\85\83\8c\83f\83B\83\93\83K\81[\82Ì\94L");
- else if (deadcat)
-/*JP
- putstr(tmpwin, 0, "Schroedinger's dead cat");
-*/
- putstr(tmpwin, 0, "\83V\83\85\83\8c\83f\83B\83\93\83K\81[\82Ì\94L\82Ì\8e\80\91Ì");
+ Strcpy(&buf[2], "\83V\83\85\83\8c\83f\83B\83\93\83K\81[\82Ì\94L\81I");
+ 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\82É\82Í\83V\83\85\83\8c\83f\83B\83\93\83K\81[\82Ì\94L%s\82ª\93ü\82Á\82Ä\82¢\82½\81I", xname(box),
- deadcat ? "\82Ì\8e\80\91Ì" : "");
-#endif
- display_nhwindow(WIN_MESSAGE, FALSE);
} else if (reportempty) {
/*JP
pline("%s is empty.", upstart(thesimpleoname(box)));
nethack_exit(status);
}
-extern const int monstr[];
-
enum vanq_order_modes {
VANQ_MLVL_MNDX = 0,
VANQ_MSTR_MNDX,
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:
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, "\93|\82µ\82½\93G\82Ì\83\\81[\83g\8f\87");
n = select_menu(tmpwin, PICK_ONE, &selected);
destroy_nhwindow(tmpwin);
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)");
#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);
pline("\93|\82µ\82½\93G\82Í\82¢\82È\82©\82Á\82½\81D");
#ifdef DUMPLOG
} else if (dumping) {
+#if 0 /*JP:T*/
putstr(0, 0, "No creatures were vanquished."); /* not pline() */
+#else
+ putstr(0, 0, "\93|\82µ\82½\93G\82Í\82¢\82È\82©\82Á\82½\81D"); /* not pline() */
+#endif
#endif
}
}
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" : "");
}
#ifdef DUMPLOG
} else if (dumping) {
+/*JP
putstr(0, 0, "No species were genocided or became extinct.");
+*/
+ putstr(0, 0, "\8bs\8eE\82µ\82½\82è\90â\96Å\82³\82¹\82½\82è\82µ\82½\8eí\82Í\82¢\82È\82©\82Á\82½\81D");
#endif
}
}
{
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;
}
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);
}
}
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)) {
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));
}
}
}
*inp = in;
}
+/*JP: files.c\82Å1\83\96\8f\8a\8eg\82í\82ê\82Ä\82¢\82é\82ª\82±\82±\82Í\89p\8cê\82Ì\82Ü\82Ü\82É\82µ\82Ä\82¨\82*/
char *
build_english_list(in)
char *in;