1 /* NetHack 3.6 end.c $NHDT-Date: 1575245059 2019/12/02 00:04:19 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.181 $ */
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 #define NEED_VARARGS /* comment line for pre-compiled headers */
19 /* add b to long a, convert wraparound to max value */
20 #define nowrap_add(a, b) (a = ((a + b) < 0 ? LONG_MAX : (a + b)))
22 /* these probably ought to be generated by makedefs, like LAST_GEM */
23 #define FIRST_GEM DILITHIUM_CRYSTAL
24 #define FIRST_AMULET AMULET_OF_ESP
25 #define LAST_AMULET AMULET_OF_YENDOR
27 struct valuable_data {
32 static struct valuable_data
33 gems[LAST_GEM + 1 - FIRST_GEM + 1], /* 1 extra for glass */
34 amulets[LAST_AMULET + 1 - FIRST_AMULET];
36 static struct val_list {
37 struct valuable_data *list;
39 } valuables[] = { { gems, sizeof gems / sizeof *gems },
40 { amulets, sizeof amulets / sizeof *amulets },
44 STATIC_PTR void FDECL(done_intr, (int));
45 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
46 static void FDECL(done_hangup, (int));
49 STATIC_DCL void FDECL(disclose, (int, BOOLEAN_P));
50 STATIC_DCL void FDECL(get_valuables, (struct obj *));
51 STATIC_DCL void FDECL(sort_valuables, (struct valuable_data *, int));
52 STATIC_DCL void NDECL(done_object_cleanup);
53 STATIC_DCL void FDECL(artifact_score, (struct obj *, BOOLEAN_P, winid));
54 STATIC_DCL void FDECL(really_done, (int)) NORETURN;
55 STATIC_DCL void FDECL(savelife, (int));
56 STATIC_PTR int FDECL(CFDECLSPEC vanqsort_cmp, (const genericptr,
58 STATIC_DCL int NDECL(set_vanq_order);
59 STATIC_DCL void FDECL(list_vanquished, (CHAR_P, BOOLEAN_P));
60 STATIC_DCL void FDECL(list_genocided, (CHAR_P, BOOLEAN_P));
61 STATIC_DCL boolean FDECL(should_query_disclose_option, (int, char *));
63 STATIC_DCL void NDECL(dump_plines);
65 STATIC_DCL void FDECL(dump_everything, (int, time_t));
66 STATIC_DCL int NDECL(num_extinct);
68 #if defined(__BEOS__) || defined(MICRO) || defined(OS2)
69 extern void FDECL(nethack_exit, (int));
71 #define nethack_exit exit
74 #define done_stopprint program_state.stopprint
77 #define NH_abort NH_abort_
81 #define NH_abort_() Abort(0)
84 #define NH_abort_() (void) abort()
87 #define NH_abort_() win32_abort()
89 #define NH_abort_() abort()
96 #ifdef PANICTRACE_LIBC
100 /* What do we try and in what order? Tradeoffs:
101 * libc: +no external programs required
102 * -requires newish libc/glibc
103 * -requires -rdynamic
104 * gdb: +gives more detailed information
105 * +works on more OS versions
106 * -requires -g, which may preclude -O on some compilers
109 #define SYSOPT_PANICTRACE_GDB sysopt.panictrace_gdb
110 #ifdef PANICTRACE_LIBC
111 #define SYSOPT_PANICTRACE_LIBC sysopt.panictrace_libc
113 #define SYSOPT_PANICTRACE_LIBC 0
116 #define SYSOPT_PANICTRACE_GDB (nh_getenv("NETHACK_USE_GDB") == 0 ? 0 : 2)
117 #ifdef PANICTRACE_LIBC
118 #define SYSOPT_PANICTRACE_LIBC 1
120 #define SYSOPT_PANICTRACE_LIBC 0
124 static void NDECL(NH_abort);
126 static void FDECL(panictrace_handler, (int));
128 static boolean NDECL(NH_panictrace_libc);
129 static boolean NDECL(NH_panictrace_gdb);
132 /* called as signal() handler, so sent at least one arg */
135 panictrace_handler(sig_unused)
136 int sig_unused UNUSED;
138 #define SIG_MSG "\nSignal received.\n"
141 f2 = (int) write(2, SIG_MSG, sizeof SIG_MSG - 1);
142 nhUse(f2); /* what could we do if write to fd#2 (stderr) fails */
143 NH_abort(); /* ... and we're already in the process of quitting? */
147 panictrace_setsignals(set)
150 #define SETSIGNAL(sig) \
151 (void) signal(sig, set ? (SIG_RET_TYPE) panictrace_handler : SIG_DFL);
171 SETSIGNAL(SIGSTKFLT);
181 #endif /* NO_SIGNAL */
186 int gdb_prio = SYSOPT_PANICTRACE_GDB;
187 int libc_prio = SYSOPT_PANICTRACE_LIBC;
188 static boolean aborting = FALSE;
195 if (gdb_prio == libc_prio && gdb_prio > 0)
198 if (gdb_prio > libc_prio) {
199 (void) (NH_panictrace_gdb() || (libc_prio && NH_panictrace_libc()));
201 (void) (NH_panictrace_libc() || (gdb_prio && NH_panictrace_gdb()));
205 /* overload otherwise unused priority for debug mode: 1 = show
206 traceback and exit; 2 = show traceback and stay in debugger */
207 /* if (wizard && gdb_prio == 1) gdb_prio = 2; */
208 vms_traceback(gdb_prio);
214 panictrace_setsignals(FALSE);
222 #ifdef PANICTRACE_LIBC
227 raw_print("Generating more information you may report:\n");
228 count = backtrace(bt, SIZE(bt));
229 info = backtrace_symbols(bt, count);
230 for (x = 0; x < count; x++) {
231 raw_printf("[%lu] %s", (unsigned long) x, info[x]);
233 /* free(info); -- Don't risk it. */
237 #endif /* !PANICTRACE_LIBC */
241 * fooPATH file system path for foo
242 * fooVAR (possibly const) variable containing fooPATH
244 #ifdef PANICTRACE_GDB
246 #define GDBVAR sysopt.gdbpath
247 #define GREPVAR sysopt.greppath
249 #define GDBVAR GDBPATH
250 #define GREPVAR GREPPATH
252 #endif /* PANICTRACE_GDB */
257 #ifdef PANICTRACE_GDB
258 /* A (more) generic method to get a stack trace - invoke
260 const char *gdbpath = GDBVAR;
261 const char *greppath = GREPVAR;
265 if (gdbpath == NULL || gdbpath[0] == 0)
267 if (greppath == NULL || greppath[0] == 0)
270 sprintf(buf, "%s -n -q %s %d 2>&1 | %s '^#'",
271 gdbpath, ARGV0, getpid(), greppath);
272 gdb = popen(buf, "w");
274 raw_print("Generating more information you may report:\n");
275 fprintf(gdb, "bt\nquit\ny");
285 #endif /* !PANICTRACE_GDB */
287 #endif /* PANICTRACE */
289 #if 0 /*JP*//*
\93ú
\96{
\8cê
\82Å
\82Í
\8eg
\82í
\82È
\82¢*/
291 * The order of these needs to match the macros in hack.h.
293 static NEARDATA const char *deaths[] = {
294 /* the array of death */
295 "died", "choked", "poisoned", "starvation", "drowning", "burning",
296 "dissolving under the heat and pressure", "crushed", "turned to stone",
297 "turned into slime", "genocided", "panic", "trickery", "quit",
298 "escaped", "ascended"
302 static NEARDATA const char *ends[] = {
305 "died", "choked", "were poisoned",
306 "starved", "drowned", "burned",
307 "dissolved in the lava",
308 "were crushed", "turned to stone",
309 "turned into slime", "were genocided",
310 "panicked", "were tricked", "quit",
311 "escaped", "ascended"
312 #else /*JP:
\8dÅ
\8cã
\82É
\81u
\8eE
\82³
\82ê
\82½
\81v
\92Ç
\89Á */
313 "
\8e\80\82ñ
\82¾", "
\92\82\91§
\82µ
\82½", "
\93Å
\82É
\82¨
\82©
\82³
\82ê
\82½",
314 "
\89ì
\8e\80\82µ
\82½", "
\93M
\8e\80\82µ
\82½", "
\8fÄ
\8e\80\82µ
\82½",
315 "
\97n
\8aâ
\82É
\97n
\82¯
\82½",
316 "
\89\9f\82µ
\92×
\82³
\82ê
\82½", "
\90Î
\82É
\82È
\82Á
\82½",
317 "
\82Ç
\82ë
\82Ç
\82ë
\82É
\97n
\82¯
\82½", "
\8bs
\8eE
\82³
\82ê
\82½",
318 "
\83p
\83j
\83b
\83N
\82É
\82¨
\82¿
\82¢
\82Á
\82½", "
\8aï
\96
\82È
\8fo
\97\88\8e\96\82É
\89ï
\82Á
\82½", "
\94²
\82¯
\82½",
319 "
\92E
\8fo
\82µ
\82½", "
\8f¸
\93V
\82µ
\82½", "
\8eE
\82³
\82ê
\82½"
323 static boolean Schroedingers_cat = FALSE;
327 done1(sig_unused) /* called as signal() handler, so sent at least one arg */
328 int sig_unused UNUSED;
331 (void) signal(SIGINT, SIG_IGN);
335 (void) signal(SIGINT, (SIG_RET_TYPE) done1);
337 clear_nhwindow(WIN_MESSAGE);
347 /* "#quit" command or keyboard interrupt */
351 if (iflags.debug_fuzzer)
354 if (!paranoid_query(ParanoidQuit, "Really quit?")) {
356 if (!paranoid_query(ParanoidQuit, "
\96{
\93\96\82É
\82â
\82ß
\82é
\81H")) {
358 (void) signal(SIGINT, (SIG_RET_TYPE) done1);
360 clear_nhwindow(WIN_MESSAGE);
366 u.uinvulnerable = FALSE; /* avoid ctrl-C bug -dlc */
371 #if (defined(UNIX) || defined(VMS) || defined(LATTICE))
375 extern int debuggable; /* sys/vms/vmsmisc.c, vmsunix.c */
377 c = !debuggable ? 'n' : ynq("Enter debugger?");
380 c = ynq("Create SnapShot?");
382 c = ynq("Dump core?");
387 (void) signal(SIGINT, (SIG_RET_TYPE) done1);
389 exit_nhwindows((char *) 0);
404 done_intr(sig_unused) /* called as signal() handler, so sent at least 1 arg */
405 int sig_unused UNUSED;
408 (void) signal(SIGINT, SIG_IGN);
409 #if defined(UNIX) || defined(VMS)
410 (void) signal(SIGQUIT, SIG_IGN);
415 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
416 /* signal() handler */
421 program_state.done_hup++;
422 sethanguphandler((void FDECL((*), (int) )) SIG_IGN);
427 #endif /* NO_SIGNAL */
430 done_in_by(mtmp, how)
435 struct permonst *mptr = mtmp->data,
436 *champtr = ((mtmp->cham >= LOW_PM)
439 boolean distorted = (boolean) (Hallucination && canspotmon(mtmp)),
440 mimicker = (M_AP_TYPE(mtmp) == M_AP_MONSTER),
441 imitator = (mptr != champtr || mimicker);
444 You((how == STONING) ? "turn to stone..." : "die...");
446 You((how == STONING) ? "
\90Î
\82É
\82È
\82Á
\82½
\81D
\81D
\81D" : "
\8e\80\82É
\82Ü
\82µ
\82½
\81D
\81D
\81D");
447 mark_synch(); /* flush buffered screen output */
449 killer.format = KILLED_BY_AN;
450 #if 0 /*JP*//*
\93ú
\96{
\8cê
\82É
\82Í
\8aÖ
\8cW
\82È
\82¢
\82Ì
\82Å
\82Ü
\82Æ
\82ß
\82Ä
\83R
\83\81\83\93\83g
\83A
\83E
\83g */
451 /* "killed by the high priest of Crom" is okay,
452 "killed by the high priest" alone isn't */
453 if ((mptr->geno & G_UNIQ) != 0 && !(imitator && !mimicker)
454 && !(mptr == &mons[PM_HIGH_PRIEST] && !mtmp->ispriest)) {
455 if (!type_is_pname(mptr))
457 killer.format = KILLED_BY;
459 /* _the_ <invisible> <distorted> ghost of Dudley */
460 if (mptr == &mons[PM_GHOST] && has_mname(mtmp)) {
462 killer.format = KILLED_BY;
467 Strcat(buf, "invisible ");
469 Strcat(buf, "
\93§
\96¾
\82È");
472 Strcat(buf, "hallucinogen-distorted ");
474 Strcat(buf, "
\8c¶
\8ao
\82Å
\98c
\82ñ
\82¾");
478 const char *realnm = champtr->mname, *fakenm = mptr->mname;
479 boolean alt = is_vampshifter(mtmp);
482 /* realnm is already correct because champtr==mptr;
483 set up fake mptr for type_is_pname/the_unique_pm */
484 mptr = &mons[mtmp->mappearance];
485 fakenm = mptr->mname;
487 } else if (alt && strstri(realnm, "vampire")
488 && !strcmp(fakenm, "vampire bat")) {
489 /* special case: use "vampire in bat form" in preference
490 to redundant looking "vampire in vampire bat form" */
493 } else if (alt && strstri(realnm, "
\8bz
\8c\8c\8bS")
494 && !strcmp(fakenm, "
\8bz
\8c\8c\82±
\82¤
\82à
\82è")) {
495 /*
\81u
\8bz
\8c\8c\82±
\82¤
\82à
\82è
\82Ì
\8ep
\82Ì
\8bz
\8c\8c\8bS
\81v
\82Í
\8fç
\92·
\82È
\82Ì
\82Å
496 \81u
\82±
\82¤
\82à
\82è
\82Ì
\8ep
\82Ì
\8bz
\8c\8c\8bS
\81v
\82Ì
\8c`
\82É
\82·
\82é */
497 fakenm = "
\82±
\82¤
\82à
\82è";
501 /* for the alternate format, always suppress any article;
502 pname and the_unique should also have s_suffix() applied,
503 but vampires don't take on any shapes which warrant that */
504 if (alt || type_is_pname(mptr)) /* no article */
505 Strcpy(shape, fakenm);
506 else if (the_unique_pm(mptr)) /* "the"; don't use the() here */
507 Sprintf(shape, "the %s", fakenm);
509 Strcpy(shape, an(fakenm));
510 #else /*JP:
\93ú
\96{
\8cê
\82Å
\82Í
\83V
\83\93\83v
\83\8b*/
511 Strcpy(shape, fakenm);
513 /* omit "called" to avoid excessive verbosity */
516 alt ? "%s in %s form"
517 : mimicker ? "%s disguised as %s"
522 alt ? "%s
\82Ì
\8ep
\82Ì%s"
523 : mimicker ? "%s
\82Ì
\82Ó
\82è
\82ð
\82µ
\82Ä
\82¢
\82é%s"
524 : "%s
\82Ì
\82Ü
\82Ë
\82ð
\82µ
\82Ä
\82¢
\82é%s",
527 mptr = mtmp->data; /* reset for mimicker case */
528 } else if (mptr == &mons[PM_GHOST]) {
530 Strcat(buf, "ghost");
532 Sprintf(eos(buf), " of %s", MNAME(mtmp));
535 Sprintf(eos(buf), "%s
\82Ì
\97H
\97ì", MNAME(mtmp));
537 Strcat(buf, "
\97H
\97ì");
539 } else if (mtmp->isshk) {
541 const char *shknm = shkname(mtmp),
542 *honorific = shkname_is_pname(mtmp) ? ""
543 : mtmp->female ? "Ms. " : "Mr. ";
545 Sprintf(eos(buf), "%s%s, the shopkeeper", honorific, shknm);
547 Sprintf(eos(buf), "%s
\82Æ
\82¢
\82¤
\96¼
\82Ì
\93X
\8eå", shkname(mtmp));
549 killer.format = KILLED_BY;
550 } else if (mtmp->ispriest || mtmp->isminion) {
551 /* m_monnam() suppresses "the" prefix plus "invisible", and
552 it overrides the effect of Hallucination on priestname() */
553 Strcat(buf, m_monnam(mtmp));
556 Strcat(buf, mptr->mname);
558 Sprintf(eos(buf), " called %s", MNAME(mtmp));
560 Strcat(buf, mptr->mname);
564 Strcpy(killer.name, buf);
566 * Chicken and egg issue:
567 * Ordinarily Unchanging ought to override something like this,
568 * but the transformation occurs at death. With the current code,
569 * the effectiveness of Unchanging stops first, but a case could
570 * be made that it should last long enough to prevent undead
571 * transformation. (Turning to slime isn't an issue here because
572 * Unchanging prevents that from happening.)
574 if (mptr->mlet == S_WRAITH)
575 u.ugrave_arise = PM_WRAITH;
576 else if (mptr->mlet == S_MUMMY && urace.mummynum != NON_PM)
577 u.ugrave_arise = urace.mummynum;
578 else if (mptr->mlet == S_VAMPIRE && Race_if(PM_HUMAN))
579 u.ugrave_arise = PM_VAMPIRE;
580 else if (mptr == &mons[PM_GHOUL])
581 u.ugrave_arise = PM_GHOUL;
582 /* this could happen if a high-end vampire kills the hero
583 when ordinary vampires are genocided; ditto for wraiths */
584 if (u.ugrave_arise >= LOW_PM
585 && (mvitals[u.ugrave_arise].mvflags & G_GENOD))
586 u.ugrave_arise = NON_PM;
591 topten.c
\82Ì killed_by_prefix
\82ð
\8eQ
\8fÆ
\82Ì
\82±
\82Æ
\81B
592 STONING
\82Ì
\8fê
\8d\87\82Í "
\90Î
\89»
\82µ
\82½"
\82ª
\95â
\82í
\82ê
\82é
\81B
594 Strcat(buf, "
\82Ì
\8dU
\8c\82\82Å");
598 DIED
\82Ì
\8fê
\8d\87\82Í
\92Ê
\8fí "
\8e\80\82ñ
\82¾"
\82ª
\95â
\82í
\82ê
\82é
\82ª
\81A
599 \89ö
\95¨
\82É
\82æ
\82é
\8fê
\8d\87\82Í "
\82É
\8eE
\82³
\82ê
\82½"
\82ð
\95â
\82¤
\81B
601 killer.format = KILLED_SUFFIX;
608 /* some special cases for overriding while-helpless reason */
609 #if 0 /*JP*//*
\93ú
\96{
\8cê
\82Å
\82Í
\8eg
\82í
\82È
\82¢*/
610 static const struct {
612 const char *exclude, *include;
614 /* "petrified by <foo>, while getting stoned" -- "while getting stoned"
615 prevented any last-second recovery, but it was not the cause of
616 "petrified by <foo>" */
617 { STONING, 1, "getting stoned", (char *) 0 },
618 /* "died of starvation, while fainted from lack of food" is accurate
619 but sounds a fairly silly (and doesn't actually appear unless you
620 splice together death and while-helpless from xlogfile) */
621 { STARVING, 0, "fainted from lack of food", "fainted" },
624 /* clear away while-helpless when the cause of death caused that
625 helplessness (ie, "petrified by <foo> while getting stoned") */
633 for (i = 0; i < SIZE(death_fixups); ++i)
634 if (death_fixups[i].why == how
635 && !strcmp(death_fixups[i].exclude, multi_reason)) {
636 if (death_fixups[i].include) /* substitute alternate reason */
637 multi_reason = death_fixups[i].include;
638 else /* remove the helplessness reason */
639 multi_reason = (char *) 0;
640 if (death_fixups[i].unmulti) /* possibly hide helplessness */
648 #if defined(WIN32) && !defined(SYSCF)
649 #define NOTIFY_NETHACK_BUGS
654 VA_DECL(const char *, str)
657 VA_INIT(str, char *);
659 if (program_state.panicking++)
660 NH_abort(); /* avoid loops - this should never happen*/
662 if (iflags.window_inited) {
663 raw_print("\r\nOops...");
664 wait_synch(); /* make sure all pending output gets flushed */
665 exit_nhwindows((char *) 0);
666 iflags.window_inited = 0; /* they're gone; force raw_print()ing */
669 raw_print(program_state.gameover
671 ? "Postgame wrapup disrupted."
673 ? "
\83Q
\81[
\83\80\8fI
\97¹
\8e\9e\82Ì
\8f\88\97\9d\82ª
\95ö
\89ó
\82µ
\82½
\81D"
674 : !program_state.something_worth_saving
676 ? "Program initialization has failed."
678 ? "
\83v
\83\8d\83O
\83\89\83\80\82Ì
\8f\89\8aú
\89»
\82É
\8e¸
\94s
\82µ
\82½
\81D"
680 : "Suddenly, the dungeon collapses.");
682 : "
\93Ë
\91R
\96À
\8b{
\82ª
\95ö
\82ê
\82½
\81D");
684 #ifdef NOTIFY_NETHACK_BUGS
686 raw_printf("Report the following error to \"%s\" or at \"%s\".",
687 DEVTEAM_EMAIL, DEVTEAM_URL);
688 else if (program_state.something_worth_saving)
689 raw_print("\nError save file being written.\n");
690 #else /* !NOTIFY_NETHACK_BUGS */
693 const char *maybe_rebuild = !program_state.something_worth_saving
695 : "\nand it may be possible to rebuild.";
697 const char *maybe_rebuild = !program_state.something_worth_saving
699 : "\n
\95\9c\8b\8c\82Å
\82«
\82é
\89Â
\94\
\90«
\82ª
\82 \82è
\82Ü
\82·
\81D";
703 raw_printf("To report this error, %s%s", sysopt.support,
705 else if (sysopt.fmtd_wizard_list) /* formatted SYSCF WIZARDS */
706 raw_printf("To report this error, contact %s%s",
707 sysopt.fmtd_wizard_list, maybe_rebuild);
710 raw_printf("Report error to \"%s\"%s", WIZARD_NAME,
713 raw_printf("\"%s\"
\82É
\83G
\83\89\81[
\82ð
\95ñ
\8d\90\82µ
\82Ä
\82
\82¾
\82³
\82¢
\81D%s", WIZARD_NAME,
717 #endif /* ?NOTIFY_NETHACK_BUGS */
718 /* XXX can we move this above the prints? Then we'd be able to
719 * suppress "it may be possible to rebuild" based on dosave0()
720 * or say it's NOT possible to rebuild. */
721 if (program_state.something_worth_saving && !iflags.debug_fuzzer) {
722 set_error_savefile();
724 /* os/win port specific recover instructions */
726 raw_printf("%s", sysopt.recover);
733 #if !defined(NO_VSNPRINTF)
734 (void) vsnprintf(buf, sizeof buf, str, VA_ARGS);
736 Vsprintf(buf, str, VA_ARGS);
739 paniclog("panic", buf);
742 interject(INTERJECT_PANIC);
744 #if defined(UNIX) || defined(VMS) || defined(LATTICE) || defined(WIN32)
746 NH_abort(); /* generate core dump */
749 really_done(PANICKED);
753 should_query_disclose_option(category, defquery)
761 if ((dop = index(disclosure_options, category)) != 0) {
762 idx = (int) (dop - disclosure_options);
763 if (idx < 0 || idx >= NUM_DISCLOSURE_OPTIONS) {
765 "should_query_disclose_option: bad disclosure index %d %c",
767 *defquery = DISCLOSE_PROMPT_DEFAULT_YES;
770 disclose = flags.end_disclose[idx];
771 if (disclose == DISCLOSE_YES_WITHOUT_PROMPT) {
774 } else if (disclose == DISCLOSE_SPECIAL_WITHOUT_PROMPT) {
777 } else if (disclose == DISCLOSE_NO_WITHOUT_PROMPT) {
780 } else if (disclose == DISCLOSE_PROMPT_DEFAULT_YES) {
783 } else if (disclose == DISCLOSE_PROMPT_DEFAULT_SPECIAL) {
791 impossible("should_query_disclose_option: bad category %c", category);
800 char buf[BUFSZ], **strp;
801 extern char *saved_plines[];
802 extern unsigned saved_pline_index;
804 Strcpy(buf, " "); /* one space for indentation */
806 putstr(0, 0, "Latest messages:");
808 putstr(0, 0, "
\8dÅ
\8cã
\82Ì
\83\81\83b
\83Z
\81[
\83W:");
809 for (i = 0, j = (int) saved_pline_index; i < DUMPLOG_MSG_COUNT;
810 ++i, j = (j + 1) % DUMPLOG_MSG_COUNT) {
811 strp = &saved_plines[j];
813 copynchars(&buf[1], *strp, BUFSZ - 1 - 1);
815 #ifdef FREE_ALL_MEMORY
816 free(*strp), *strp = 0;
825 dump_everything(how, when)
827 time_t when; /* date+time at end of game */
830 char pbuf[BUFSZ], datetimebuf[24]; /* [24]: room for 64-bit bogus value */
833 if (!iflags.in_dumplog)
836 init_symbols(); /* revert to default symbol set */
838 /* one line version ID, which includes build date+time;
839 it's conceivable that the game started with a different
840 build date+time or even with an older nethack version,
841 but we only have access to the one it finished under */
842 putstr(0, 0, getversionstring(pbuf));
844 putstr(0, 0, version_string_j(pbuf));
848 /* game start and end date+time to disambiguate version date+time */
849 Strcpy(datetimebuf, yyyymmddhhmmss(ubirthday));
851 Sprintf(pbuf, "Game began %4.4s-%2.2s-%2.2s %2.2s:%2.2s:%2.2s",
852 &datetimebuf[0], &datetimebuf[4], &datetimebuf[6],
853 &datetimebuf[8], &datetimebuf[10], &datetimebuf[12]);
855 Sprintf(pbuf, "
\83Q
\81[
\83\80\8aJ
\8en %4.4s-%2.2s-%2.2s %2.2s:%2.2s:%2.2s",
856 &datetimebuf[0], &datetimebuf[4], &datetimebuf[6],
857 &datetimebuf[8], &datetimebuf[10], &datetimebuf[12]);
859 Strcpy(datetimebuf, yyyymmddhhmmss(when));
861 Sprintf(eos(pbuf), ", ended %4.4s-%2.2s-%2.2s %2.2s:%2.2s:%2.2s.",
862 &datetimebuf[0], &datetimebuf[4], &datetimebuf[6],
863 &datetimebuf[8], &datetimebuf[10], &datetimebuf[12]);
865 Sprintf(eos(pbuf), ",
\8fI
\97¹ %4.4s-%2.2s-%2.2s %2.2s:%2.2s:%2.2s.",
866 &datetimebuf[0], &datetimebuf[4], &datetimebuf[6],
867 &datetimebuf[8], &datetimebuf[10], &datetimebuf[12]);
872 /* character name and basic role info */
873 Sprintf(pbuf, "%s, %s %s %s %s", plname,
874 aligns[1 - u.ualign.type].adj,
875 genders[flags.female].adj,
877 (flags.female && urole.name.f) ? urole.name.f : urole.name.m);
882 putstr(0, 0, do_statusline1());
883 putstr(0, 0, do_statusline2());
889 putstr(0, 0, "Inventory:");
891 putstr(0, 0, "
\8e\9d\82¿
\95¨:");
892 (void) display_inventory((char *) 0, TRUE);
893 container_contents(invent, TRUE, TRUE, FALSE);
894 enlightenment((BASICENLIGHTENMENT | MAGICENLIGHTENMENT),
895 (how >= PANICKED) ? ENL_GAMEOVERALIVE : ENL_GAMEOVERDEAD);
897 list_vanquished('d', FALSE); /* 'd' => 'y' */
899 list_genocided('d', FALSE); /* 'd' => 'y' */
901 show_conduct((how >= PANICKED) ? 1 : 2);
903 show_overview((how >= PANICKED) ? 1 : 2, how);
905 dump_redirect(FALSE);
917 char c = '\0', defquery;
921 if (invent && !done_stopprint) {
924 Sprintf(qbuf, "Do you want to see what you had when you %s?",
925 (how == QUIT) ? "quit" : "died");
927 Sprintf(qbuf,"%s
\82Æ
\82«
\89½
\82ð
\8e\9d\82Á
\82Ä
\82¢
\82½
\82©
\8c©
\82Ü
\82·
\82©
\81H",
928 (how == QUIT) ? "
\82â
\82ß
\82½" : "
\8e\80\82ñ
\82¾");
932 Strcpy(qbuf, "Do you want your possessions identified?");
934 Strcpy(qbuf,"
\8e\9d\82¿
\95¨
\82ð
\8e¯
\95Ê
\82µ
\82Ü
\82·
\82©
\81H");
936 ask = should_query_disclose_option('i', &defquery);
937 c = ask ? yn_function(qbuf, ynqchars, defquery) : defquery;
939 /* caller has already ID'd everything */
940 (void) display_inventory((char *) 0, TRUE);
941 container_contents(invent, TRUE, TRUE, FALSE);
947 if (!done_stopprint) {
948 ask = should_query_disclose_option('a', &defquery);
950 c = ask ? yn_function("Do you want to see your attributes?", ynqchars,
954 c = ask ? yn_function("
\91®
\90«
\82ð
\8c©
\82Ü
\82·
\82©
\81H", ynqchars,
959 enlightenment((BASICENLIGHTENMENT | MAGICENLIGHTENMENT),
960 (how >= PANICKED) ? ENL_GAMEOVERALIVE
966 if (!done_stopprint) {
967 ask = should_query_disclose_option('v', &defquery);
968 list_vanquished(defquery, ask);
971 if (!done_stopprint) {
972 ask = should_query_disclose_option('g', &defquery);
973 list_genocided(defquery, ask);
976 if (!done_stopprint) {
977 ask = should_query_disclose_option('c', &defquery);
979 c = ask ? yn_function("Do you want to see your conduct?", ynqchars,
983 c = ask ? yn_function("
\82Ç
\82¤
\82¢
\82¤
\8ds
\93®
\82ð
\82Æ
\82Á
\82½
\82©
\8c©
\82Ü
\82·
\82©
\81H", ynqchars,
988 show_conduct((how >= PANICKED) ? 1 : 2);
993 if (!done_stopprint) {
994 ask = should_query_disclose_option('o', &defquery);
996 c = ask ? yn_function("Do you want to see the dungeon overview?",
1000 c = ask ? yn_function("
\96À
\8b{
\82Ì
\8aT
\97v
\82ð
\8c©
\82Ü
\82·
\82©
\81H",
1005 show_overview((how >= PANICKED) ? 1 : 2, how);
1011 /* try to get the player back in a viable state after being killed */
1016 int uhpmin = max(2 * u.ulevel, 10);
1018 if (u.uhpmax < uhpmin)
1021 if (Upolyd) /* Unchanging, or death which bypasses losing hit points */
1023 if (u.uhunger < 500 || how == CHOKING) {
1026 /* cure impending doom of sickness hero won't have time to fix */
1027 if ((Sick & TIMEOUT) == 1L) {
1028 make_sick(0L, (char *) 0, FALSE, SICK_ALL);
1031 nomovemsg = "You survived that attempt on your life.";
1033 nomovemsg = "
\82 \82È
\82½
\82Í
\90¶
\82«
\82È
\82ª
\82ç
\82¦
\82½
\81D";
1039 if (u.utrap && u.utraptype == TT_LAVA)
1042 u.ugrave_arise = NON_PM;
1045 if (!context.mon_moving)
1046 endmultishot(FALSE);
1048 /* might drop hero onto a trap that kills her all over again */
1049 expels(u.ustuck, u.ustuck->data, TRUE);
1050 } else if (u.ustuck) {
1051 if (Upolyd && sticks(youmonst.data))
1052 You("release %s.", mon_nam(u.ustuck));
1054 pline("%s releases you.", Monnam(u.ustuck));
1060 * Get valuables from the given list. Revised code: the list always remains
1065 struct obj *list; /* inventory or container contents */
1067 register struct obj *obj;
1070 /* find amulets and gems, ignoring all artifacts */
1071 for (obj = list; obj; obj = obj->nobj)
1072 if (Has_contents(obj)) {
1073 get_valuables(obj->cobj);
1074 } else if (obj->oartifact) {
1076 } else if (obj->oclass == AMULET_CLASS) {
1077 i = obj->otyp - FIRST_AMULET;
1078 if (!amulets[i].count) {
1079 amulets[i].count = obj->quan;
1080 amulets[i].typ = obj->otyp;
1082 amulets[i].count += obj->quan; /* always adds one */
1083 } else if (obj->oclass == GEM_CLASS && obj->otyp < LUCKSTONE) {
1084 i = min(obj->otyp, LAST_GEM + 1) - FIRST_GEM;
1085 if (!gems[i].count) {
1086 gems[i].count = obj->quan;
1087 gems[i].typ = obj->otyp;
1089 gems[i].count += obj->quan;
1095 * Sort collected valuables, most frequent to least. We could just
1096 * as easily use qsort, but we don't care about efficiency here.
1099 sort_valuables(list, size)
1100 struct valuable_data list[];
1101 int size; /* max value is less than 20 */
1104 struct valuable_data ltmp;
1106 /* move greater quantities to the front of the list */
1107 for (i = 1; i < size; i++) {
1108 if (list[i].count == 0)
1109 continue; /* empty slot */
1110 ltmp = list[i]; /* structure copy */
1111 for (j = i; j > 0; --j)
1112 if (list[j - 1].count >= ltmp.count)
1115 list[j] = list[j - 1];
1124 * odds_and_ends() was used for 3.6.0 and 3.6.1.
1125 * Schroedinger's Cat is handled differently as of 3.6.2.
1127 STATIC_DCL boolean FDECL(odds_and_ends, (struct obj *, int));
1132 odds_and_ends(list, what)
1138 for (otmp = list; otmp; otmp = otmp->nobj) {
1140 case CAT_CHECK: /* Schroedinger's Cat */
1141 /* Ascending is deterministic */
1142 if (SchroedingersBox(otmp))
1146 if (Has_contents(otmp))
1147 return odds_and_ends(otmp->cobj, what);
1153 /* deal with some objects which may be in an abnormal state at end of game */
1155 done_object_cleanup()
1159 /* might have been killed while using a disposable item, so make sure
1160 it's gone prior to inventory disclosure and creation of bones */
1163 * Hero can die when throwing an object (by hitting an adjacent
1164 * gas spore, for instance, or being hit by mis-returning Mjollnir),
1165 * or while in transit (from falling down stairs). If that happens,
1166 * some object(s) might be in limbo rather than on the map or in
1167 * any inventory. Saving bones with an active light source in limbo
1168 * would trigger an 'object not local' panic.
1170 * We used to use dealloc_obj() on thrownobj and kickedobj but
1171 * that keeps them out of bones and could leave uball in a confused
1172 * state (gone but still attached). Place them on the map but
1173 * bypass flooreffects(). That could lead to minor anomalies in
1174 * bones, like undamaged paper at water or lava locations or piles
1175 * not being knocked down holes, but it seems better to get this
1176 * game over with than risk being tangled up in more and more details.
1178 ox = u.ux + u.dx, oy = u.uy + u.dy;
1179 if (!isok(ox, oy) || !accessible(ox, oy))
1180 ox = u.ux, oy = u.uy;
1181 /* put thrown or kicked object on map (for bones); location might
1182 be incorrect (perhaps killed by divine lightning when throwing at
1183 a temple priest?) but this should be better than just vanishing
1184 (fragile stuff should be taken care of before getting here) */
1185 if (thrownobj && thrownobj->where == OBJ_FREE) {
1186 place_object(thrownobj, ox, oy);
1187 stackobj(thrownobj), thrownobj = 0;
1189 if (kickedobj && kickedobj->where == OBJ_FREE) {
1190 place_object(kickedobj, ox, oy);
1191 stackobj(kickedobj), kickedobj = 0;
1193 /* if Punished hero dies during level change or dies or quits while
1194 swallowed, uball and uchain will be in limbo; put them on floor
1195 so bones will have them and object list cleanup finds them */
1196 if (uchain && uchain->where == OBJ_FREE) {
1198 lift_covet_and_placebc(override_restriction);
1200 /* persistent inventory window now obsolete since disclosure uses
1201 a normal popup one; avoids "Bad fruit #n" when saving bones */
1202 if (iflags.perm_invent) {
1203 iflags.perm_invent = FALSE;
1204 update_inventory(); /* make interface notice the change */
1209 /* called twice; first to calculate total, then to list relevant items */
1211 artifact_score(list, counting, endwin)
1213 boolean counting; /* true => add up points; false => display them */
1219 short dummy; /* object type returned by artifact_name() */
1221 for (otmp = list; otmp; otmp = otmp->nobj) {
1222 if (otmp->oartifact || otmp->otyp == BELL_OF_OPENING
1223 || otmp->otyp == SPE_BOOK_OF_THE_DEAD
1224 || otmp->otyp == CANDELABRUM_OF_INVOCATION) {
1225 value = arti_cost(otmp); /* zorkmid value */
1226 points = value * 5 / 2; /* score value */
1228 nowrap_add(u.urexp, points);
1230 discover_object(otmp->otyp, TRUE, FALSE);
1231 otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
1232 /* assumes artifacts don't have quan > 1 */
1234 Sprintf(pbuf, "%s%s (worth %ld %s and %ld points)",
1235 the_unique_obj(otmp) ? "The " : "",
1236 otmp->oartifact ? artifact_name(xname(otmp), &dummy)
1237 : OBJ_NAME(objects[otmp->otyp]),
1238 value, currency(value), points);
1240 Sprintf(pbuf, "%s(%ld%s
\81C%ld
\83|
\83C
\83\93\83g
\82Ì
\89¿
\92l)
\81C",
1241 otmp->oartifact ? artifact_name(xname(otmp), &dummy)
1242 : OBJ_NAME(objects[otmp->otyp]),
1243 value, currency(value), points);
1245 putstr(endwin, 0, pbuf);
1248 if (Has_contents(otmp))
1249 artifact_score(otmp->cobj, counting, endwin);
1253 /* Be careful not to call panic from here! */
1258 boolean survive = FALSE;
1260 if (how == TRICKED) {
1261 if (killer.name[0]) {
1262 paniclog("trickery", killer.name);
1263 killer.name[0] = '\0';
1267 You("are a very tricky wizard, it seems.");
1269 You("
\82Æ
\82Ä
\82à
\88µ
\82¢
\82É
\82
\82¢wizard
\82Ì
\82æ
\82¤
\82¾
\81D");
1270 killer.format = KILLED_BY_AN; /* reset to 0 */
1274 if (program_state.panicking
1275 #ifdef HANGUPHANDLING
1276 || program_state.done_hup
1279 /* skip status update if panicking or disconnected */
1280 context.botl = context.botlx = iflags.time_botl = FALSE;
1282 /* otherwise force full status update */
1283 context.botlx = TRUE;
1287 if (iflags.debug_fuzzer) {
1288 if (!(program_state.panicking || how == PANICKED)) {
1290 /* periodically restore characteristics and lost exp levels
1291 or cure lycanthropy */
1293 struct obj *potion = mksobj((u.ulycn > LOW_PM && !rn2(3))
1294 ? POT_WATER : POT_RESTORE_ABILITY,
1298 (void) peffects(potion); /* always -1 for restore ability */
1299 /* not useup(); we haven't put this potion into inventory */
1300 obfree(potion, (struct obj *) 0);
1302 killer.name[0] = '\0';
1307 if (how == ASCENDED || (!killer.name[0] && how == GENOCIDED))
1308 killer.format = NO_KILLER_PREFIX;
1309 /* Avoid killed by "a" burning or "a" starvation */
1310 if (!killer.name[0] && (how == STARVING || how == BURNING))
1311 killer.format = KILLED_BY;
1312 if (!killer.name[0] || how >= PANICKED)
1314 Strcpy(killer.name, deaths[how]);
1316 Strcpy(killer.name, ends[how]);
1318 if (how < PANICKED) {
1320 /* in case caller hasn't already done this */
1321 if (u.uhp != 0 || (Upolyd && u.mh != 0)) {
1322 /* force HP to zero in case it is still positive (some
1323 deaths aren't triggered by loss of hit points), or
1324 negative (-1 is used as a flag in some circumstances
1325 which don't apply when actually dying due to HP loss) */
1330 if (Lifesaved && (how <= GENOCIDED)) {
1332 pline("But wait...");
1334 pline("
\82¿
\82å
\82Á
\82Æ
\82Ü
\82Á
\82½
\81D
\81D
\81D");
1335 makeknown(AMULET_OF_LIFE_SAVING);
1337 Your("medallion %s!", !Blind ? "begins to glow" : "feels warm");
1339 Your("
\96\82\8f\9c\82¯
\82Í%s
\81I", !Blind ? "
\8bP
\82«
\82Í
\82¶
\82ß
\82½" : "
\92g
\82©
\82
\82È
\82è
\82Í
\82¶
\82ß
\82½");
1344 You("
\93f
\82¢
\82½
\81D
\81D
\81D");
1346 You_feel("much better!");
1348 You("
\8bC
\95ª
\82ª
\82æ
\82
\82È
\82Á
\82½
\81I");
1350 pline_The("medallion crumbles to dust!");
1352 pline("
\96\82\8f\9c\82¯
\82Í
\82±
\82È
\82²
\82È
\82É
\82
\82¾
\82¯
\82½
\81I");
1356 (void) adjattrib(A_CON, -1, TRUE);
1358 if (how == GENOCIDED) {
1360 pline("Unfortunately you are still genocided...");
1362 pline("
\8ec
\94O
\82È
\82ª
\82ç
\81C
\82 \82È
\82½
\82Í
\8bs
\8eE
\82³
\82ê
\82½
\82Ü
\82Ü
\82¾
\81D
\81D
\81D");
1367 /* explore and wizard modes offer player the option to keep playing */
1369 if (!survive && (wizard || discover) && how <= GENOCIDED
1370 && !paranoid_query(ParanoidDie, "Die?")) {
1372 if (!survive && (wizard || discover) && how <= GENOCIDED
1373 && !paranoid_query(ParanoidDie, "
\8e\80\82ñ
\82Å
\82Ý
\82é
\81H")) {
1376 pline("OK, so you don't %s.", (how == CHOKING) ? "choke" : "die");
1378 You("
\8e\80\82È
\82È
\82©
\82Á
\82½
\81D");
1379 iflags.last_msg = PLNMSG_OK_DONT_DIE;
1385 killer.name[0] = '\0';
1386 killer.format = KILLED_BY_AN; /* reset to 0 */
1393 /* separated from done() in order to specify the __noreturn__ attribute */
1400 winid endwin = WIN_ERR;
1401 boolean bones_ok, have_windows = iflags.window_inited;
1402 struct obj *corpse = (struct obj *) 0;
1408 * The game is now over...
1410 program_state.gameover = 1;
1411 /* in case of a subsequent panic(), there's no point trying to save */
1412 program_state.something_worth_saving = 0;
1413 #ifdef HANGUPHANDLING
1414 if (program_state.done_hup)
1417 /* render vision subsystem inoperative */
1418 iflags.vision_inited = 0;
1420 /* maybe use up active invent item(s), place thrown/kicked missile,
1421 deal with ball and chain possibly being temporarily off the map */
1422 if (!program_state.panicking)
1423 done_object_cleanup();
1424 /* in case we're panicking; normally cleared by done_object_cleanup() */
1425 iflags.perm_invent = FALSE;
1427 /* remember time of death here instead of having bones, rip, and
1428 topten figure it out separately and possibly getting different
1429 time or even day if player is slow responding to --More-- */
1430 urealtime.finish_time = endtime = getnow();
1431 urealtime.realtime += (long) (endtime - urealtime.start_timing);
1432 /* collect these for end of game disclosure (not used during play) */
1433 iflags.at_night = night();
1434 iflags.at_midnight = midnight();
1436 dump_open_log(endtime);
1437 /* Sometimes you die on the first move. Life's not fair.
1438 * On those rare occasions you get hosed immediately, go out
1439 * smiling... :-) -3.
1441 if (moves <= 1 && how < PANICKED && !done_stopprint)
1443 pline("Do not pass Go. Do not collect 200 %s.", currency(200L));
1445 pline("
\92\8d\88Ó
\88ê
\95b
\81C
\89ö
\89ä
\88ê
\90¶
\81C
\8e\80\96S
\88ê
\95à
\81D");
1448 wait_synch(); /* flush screen output */
1450 (void) signal(SIGINT, (SIG_RET_TYPE) done_intr);
1451 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
1452 (void) signal(SIGQUIT, (SIG_RET_TYPE) done_intr);
1453 sethanguphandler(done_hangup);
1455 #endif /* NO_SIGNAL */
1457 bones_ok = (how < GENOCIDED) && can_make_bones();
1459 if (bones_ok && launch_in_progress())
1460 force_launch_placement();
1462 /* maintain ugrave_arise even for !bones_ok */
1463 if (how == PANICKED)
1464 u.ugrave_arise = (NON_PM - 3); /* no corpse, no grave */
1465 else if (how == BURNING || how == DISSOLVED) /* corpse burns up too */
1466 u.ugrave_arise = (NON_PM - 2); /* leave no corpse */
1467 else if (how == STONING)
1468 u.ugrave_arise = (NON_PM - 1); /* statue instead of corpse */
1469 else if (how == TURNED_SLIME
1470 /* it's possible to turn into slime even though green slimes
1471 have been genocided: genocide could occur after hero is
1472 already infected or hero could eat a glob of one created
1473 before genocide; don't try to arise as one if they're gone */
1474 && !(mvitals[PM_GREEN_SLIME].mvflags & G_GENOD))
1475 u.ugrave_arise = PM_GREEN_SLIME;
1478 killer.format = NO_KILLER_PREFIX;
1481 u.umortality++; /* skipped above when how==QUIT */
1483 Strcpy(killer.name, "quit while already on Charon's boat");
1485 Strcpy(killer.name, "
\8eO
\93r
\82Ì
\90ì
\82Ì
\93n
\82µ
\91D
\82É
\8fæ
\82Á
\82Ä
\82¢
\82é
\8aÔ
\82É
\94²
\82¯
\82½");
1488 if (how == ESCAPED || how == PANICKED)
1489 killer.format = NO_KILLER_PREFIX;
1491 #if 0 /*JP*//*
\93ú
\96{
\8cê
\82Å
\82Í
\8eg
\82í
\82È
\82¢*/
1492 fixup_death(how); /* actually, fixup multi_reason */
1495 if (how != PANICKED) {
1496 boolean silently = done_stopprint ? TRUE : FALSE;
1498 /* these affect score and/or bones, but avoid them during panic */
1499 taken = paybill((how == ESCAPED) ? -1 : (how != QUIT), silently);
1503 taken = FALSE; /* lint; assert( !bones_ok ); */
1508 display_nhwindow(WIN_MESSAGE, FALSE);
1510 if (how != PANICKED) {
1514 * This is needed for both inventory disclosure and dumplog.
1515 * Both are optional, so do it once here instead of duplicating
1516 * it in both of those places.
1518 for (obj = invent; obj; obj = obj->nobj) {
1519 discover_object(obj->otyp, TRUE, FALSE);
1520 obj->known = obj->bknown = obj->dknown = obj->rknown = 1;
1521 if (Is_container(obj) || obj->otyp == STATUE)
1522 obj->cknown = obj->lknown = 1;
1523 /* we resolve Schroedinger's cat now in case of both
1524 disclosure and dumplog, where the 50:50 chance for
1525 live cat has to be the same both times */
1526 if (SchroedingersBox(obj)) {
1527 if (!Schroedingers_cat) {
1528 /* tell observe_quantum_cat() not to create a cat; if it
1529 chooses live cat in this situation, it will leave the
1530 SchroedingersBox flag set (for container_contents()) */
1531 observe_quantum_cat(obj, FALSE, FALSE);
1532 if (SchroedingersBox(obj))
1533 Schroedingers_cat = TRUE;
1535 obj->spe = 0; /* ordinary box with cat corpse in it */
1539 if (strcmp(flags.end_disclose, "none"))
1540 disclose(how, taken);
1542 dump_everything(how, endtime);
1545 /* if pets will contribute to score, populate mydogs list now
1546 (bones creation isn't a factor, but pline() messaging is; used to
1547 be done even sooner, but we need it to come after dump_everything()
1548 so that any accompanying pets are still on the map during dump) */
1549 if (how == ESCAPED || how == ASCENDED)
1552 /* finish_paybill should be called after disclosure but before bones */
1553 if (bones_ok && taken)
1556 /* grave creation should be after disclosure so it doesn't have
1557 this grave in the current level's features for #overview */
1558 if (bones_ok && u.ugrave_arise == NON_PM
1559 && !(mvitals[u.umonnum].mvflags & G_NOCORPSE)) {
1560 int mnum = u.umonnum;
1563 /* Base corpse on race when not poly'd since original u.umonnum
1564 is based on role, and all role monsters are human. */
1565 mnum = (flags.female && urace.femalenum != NON_PM)
1569 corpse = mk_named_object(CORPSE, &mons[mnum], u.ux, u.uy, plname);
1571 Sprintf(pbuf, "%s, ", plname);
1573 Sprintf(pbuf, "%s
\82Ì
\95æ
\81C", plname);
1574 formatkiller(eos(pbuf), sizeof pbuf - strlen(pbuf), how, TRUE);
1575 make_grave(u.ux, u.uy, pbuf);
1577 pbuf[0] = '\0'; /* clear grave text; also lint suppression */
1579 /* calculate score, before creating bones [container gold] */
1581 int deepest = deepest_lev_reached(FALSE);
1583 umoney = money_cnt(invent);
1585 umoney += hidden_gold(); /* accumulate gold from containers */
1586 tmp = umoney - tmp; /* net gain */
1592 tmp += 50L * (long) (deepest - 1);
1594 tmp += 1000L * (long) ((deepest > 30) ? 10 : deepest - 20);
1595 nowrap_add(u.urexp, tmp);
1597 /* ascension gives a score bonus iff offering to original deity */
1598 if (how == ASCENDED && u.ualign.type == u.ualignbase[A_ORIGINAL]) {
1599 /* retaining original alignment: score *= 2;
1600 converting, then using helm-of-OA to switch back: *= 1.5 */
1601 tmp = (u.ualignbase[A_CURRENT] == u.ualignbase[A_ORIGINAL])
1604 nowrap_add(u.urexp, tmp);
1608 if (u.ugrave_arise >= LOW_PM && !done_stopprint) {
1609 /* give this feedback even if bones aren't going to be created,
1610 so that its presence or absence doesn't tip off the player to
1611 new bones or their lack; it might be a lie if makemon fails */
1614 (u.ugrave_arise != PM_GREEN_SLIME)
1615 ? "body rises from the dead"
1616 : "revenant persists",
1617 an(mons[u.ugrave_arise].mname));
1619 Your("%s as %s
\82É
\82È
\82Á
\82½
\81D
\81D
\81D",
1620 (u.ugrave_arise != PM_GREEN_SLIME)
1621 ? "
\91Ì
\82Í
\8e\80\91Ì
\82©
\82ç
\91h
\82Á
\82Ä"
1623 mons[u.ugrave_arise].mname);
1625 display_nhwindow(WIN_MESSAGE, FALSE);
1630 if (!wizard || paranoid_query(ParanoidBones, "Save bones?"))
1632 if (!wizard || paranoid_query(ParanoidBones, "
\8d\9c\82ð
\82¤
\82ß
\82é
\81H"))
1633 savebones(how, endtime, corpse);
1634 /* corpse may be invalid pointer now so
1635 ensure that it isn't used again */
1636 corpse = (struct obj *) 0;
1639 /* update gold for the rip output, which can't use hidden_gold()
1640 (containers will be gone by then if bones just got saved...) */
1641 done_money = umoney;
1643 /* clean up unneeded windows */
1646 free_pickinv_cache(); /* extra persistent window if perm_invent */
1647 if (WIN_INVEN != WIN_ERR) {
1648 destroy_nhwindow(WIN_INVEN), WIN_INVEN = WIN_ERR;
1649 /* precaution in case any late update_inventory() calls occur */
1650 iflags.perm_invent = 0;
1652 display_nhwindow(WIN_MESSAGE, TRUE);
1653 destroy_nhwindow(WIN_MAP), WIN_MAP = WIN_ERR;
1654 if (WIN_STATUS != WIN_ERR)
1655 destroy_nhwindow(WIN_STATUS), WIN_STATUS = WIN_ERR;
1656 destroy_nhwindow(WIN_MESSAGE), WIN_MESSAGE = WIN_ERR;
1658 if (!done_stopprint || flags.tombstone)
1659 endwin = create_nhwindow(NHW_TEXT);
1661 if (how < GENOCIDED && flags.tombstone && endwin != WIN_ERR)
1662 outrip(endwin, how, endtime);
1664 done_stopprint = 1; /* just avoid any more output */
1667 /* 'how' reasons beyond genocide shouldn't show tombstone;
1668 for normal end of game, genocide doesn't either */
1669 if (how <= GENOCIDED) {
1670 dump_redirect(TRUE);
1671 if (iflags.in_dumplog)
1672 genl_outrip(0, how, endtime);
1673 dump_redirect(FALSE);
1676 if (u.uhave.amulet) {
1678 Strcat(killer.name, " (with the Amulet)");
1680 Strcat(killer.name, "
\96\82\8f\9c\82¯
\82ð
\8eè
\82É");
1681 } else if (how == ESCAPED) {
1682 if (Is_astralevel(&u.uz)) /* offered Amulet to wrong deity */
1684 Strcat(killer.name, " (in celestial disgrace)");
1686 Strcat(killer.name, "
\93V
\8fã
\82Å
\92p
\90J
\82ð
\8eó
\82¯
\92E
\8fo
\82µ
\82½");
1687 else if (carrying(FAKE_AMULET_OF_YENDOR))
1689 Strcat(killer.name, " (with a fake Amulet)");
1691 Strcat(killer.name, "
\8bU
\95¨
\82Ì
\96\82\8f\9c\82¯
\82ð
\92Í
\82Ü
\82³
\82ê
\92E
\8fo
\82µ
\82½");
1692 /* don't bother counting to see whether it should be plural */
1696 Sprintf(pbuf, "%s %s the %s...", Goodbye(), plname,
1698 ? (const char *) ((flags.female && urole.name.f)
1701 : (const char *) (flags.female ? "Demigoddess" : "Demigod"));
1703 Sprintf(pbuf, "%s%s
\82Ì%s
\81D
\81D
\81D", Goodbye(),
1705 ? (const char *) ((flags.female && urole.name.f)
1708 : (const char *) (flags.female ? "
\8f\97\90_" : "
\90_"),
1711 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1712 dump_forward_putstr(endwin, 0, "", done_stopprint);
1714 if (how == ESCAPED || how == ASCENDED) {
1717 register struct val_list *val;
1720 for (val = valuables; val->list; val++)
1721 for (i = 0; i < val->size; i++) {
1722 val->list[i].count = 0L;
1724 get_valuables(invent);
1726 /* add points for collected valuables */
1727 for (val = valuables; val->list; val++)
1728 for (i = 0; i < val->size; i++)
1729 if (val->list[i].count != 0L) {
1730 tmp = val->list[i].count
1731 * (long) objects[val->list[i].typ].oc_cost;
1732 nowrap_add(u.urexp, tmp);
1735 /* count the points for artifacts */
1736 artifact_score(invent, TRUE, endwin);
1738 viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */
1741 Strcpy(pbuf, "You");
1743 Strcpy(pbuf, "
\82 \82È
\82½");
1744 if (mtmp || Schroedingers_cat) {
1747 Sprintf(eos(pbuf), " and %s", mon_nam(mtmp));
1749 Sprintf(eos(pbuf), "
\82Æ%s", mon_nam(mtmp));
1751 nowrap_add(u.urexp, mtmp->mhp);
1754 /* [it might be more robust to create a housecat and add it to
1755 mydogs; it doesn't have to be placed on the map for that] */
1756 if (Schroedingers_cat) {
1757 int mhp, m_lev = adj_lev(&mons[PM_HOUSECAT]);
1760 nowrap_add(u.urexp, mhp);
1762 Strcat(eos(pbuf), " and Schroedinger's cat");
1764 Strcat(eos(pbuf), "
\82Æ
\83V
\83\85\83\8c\83f
\83B
\83\93\83K
\81[
\82Ì
\94L");
1767 if (!done_stopprint)
1768 Strcat(pbuf, "
\82Í");
1770 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1776 Strcat(pbuf, "
\82Í");
1779 Sprintf(eos(pbuf), "%s with %ld point%s,",
1780 how == ASCENDED ? "went to your reward"
1781 : "escaped from the dungeon",
1782 u.urexp, plur(u.urexp));
1784 Sprintf(eos(pbuf), "%ld
\83|
\83C
\83\93\83g
\83}
\81[
\83N
\82µ%s
\81D",
1786 how==ASCENDED ? "
\8f¸
\93V
\82µ
\82½" : "
\96À
\8b{
\82©
\82ç
\92E
\8fo
\82µ
\82½");
1788 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1790 if (!done_stopprint)
1791 artifact_score(invent, FALSE, endwin); /* list artifacts */
1793 dump_redirect(TRUE);
1794 if (iflags.in_dumplog)
1795 artifact_score(invent, FALSE, 0);
1796 dump_redirect(FALSE);
1799 /* list valuables here */
1800 for (val = valuables; val->list; val++) {
1801 sort_valuables(val->list, val->size);
1802 for (i = 0; i < val->size && !done_stopprint; i++) {
1803 int typ = val->list[i].typ;
1804 long count = val->list[i].count;
1808 if (objects[typ].oc_class != GEM_CLASS || typ <= LAST_GEM) {
1809 otmp = mksobj(typ, FALSE, FALSE);
1810 discover_object(otmp->otyp, TRUE, FALSE);
1811 otmp->known = 1; /* for fake amulets */
1812 otmp->dknown = 1; /* seen it (blindness fix) */
1813 if (has_oname(otmp))
1817 Sprintf(pbuf, "%8ld %s (worth %ld %s),", count,
1818 xname(otmp), count * (long) objects[typ].oc_cost,
1821 Sprintf(pbuf, "%ld
\8cÂ
\82Ì%s(%ld%s
\82Ì
\89¿
\92l)
\81C", count,
1822 xname(otmp), count * (long) objects[typ].oc_cost,
1825 obfree(otmp, (struct obj *) 0);
1828 Sprintf(pbuf, "%8ld worthless piece%s of colored glass,",
1829 count, plur(count));
1831 Sprintf(pbuf, "%ld
\8cÂ
\82Ì
\89¿
\92l
\82Ì
\82È
\82¢
\90F
\82Â
\82«
\83K
\83\89\83X
\81C",
1835 dump_forward_putstr(endwin, 0, pbuf, 0);
1840 /* did not escape or ascend */
1841 if (u.uz.dnum == 0 && u.uz.dlevel <= 0) {
1842 /* level teleported out of the dungeon; `how' is DIED,
1843 due to falling or to "arriving at heaven prematurely" */
1845 Sprintf(pbuf, "You %s beyond the confines of the dungeon",
1846 (u.uz.dlevel < 0) ? "passed away" : ends[how]);
1848 Sprintf(pbuf, "
\96À
\8b{
\82Ì
\97Ì
\88æ
\82ð
\89z
\82¦%s
\81D",
1849 (u.uz.dlevel < 0) ? "
\8fÁ
\82¦
\82³
\82Á
\82½" : ends[how]);
1852 /* more conventional demise */
1853 const char *where = dungeons[u.uz.dnum].dname;
1855 if (Is_astralevel(&u.uz))
1857 where = "The Astral Plane";
1859 where = "
\90¸
\97ì
\8aE
\82É
\82Ä";
1861 Sprintf(pbuf, "You %s in %s", ends[how], where);
1863 Sprintf(pbuf, "
\82 \82È
\82½
\82Í%s", where);
1864 if (!In_endgame(&u.uz) && !Is_knox(&u.uz))
1866 Sprintf(eos(pbuf), " on dungeon level %d",
1867 In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz));
1869 Sprintf(eos(pbuf), "
\82Ì
\92n
\89º%d
\8aK
\82Å",
1870 In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz));
1875 Sprintf(eos(pbuf), " with %ld point%s,", u.urexp, plur(u.urexp));
1877 Sprintf(eos(pbuf), " %ld
\83|
\83C
\83\93\83g
\82ð
\83}
\81[
\83N
\82µ
\81C", u.urexp);
1878 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1882 Sprintf(pbuf, "and %ld piece%s of gold, after %ld move%s.", umoney,
1883 plur(umoney), moves, plur(moves));
1885 Sprintf(pbuf, "%ld
\96\87\82Ì
\8bà
\89Ý
\82ð
\8e\9d\82Á
\82Ä
\81C%ld
\95à
\93®
\82¢
\82½
\81D", umoney,
1888 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1891 "You were level %d with a maximum of %d hit point%s when you %s.",
1892 u.ulevel, u.uhpmax, plur(u.uhpmax), ends[how]);
1895 "%s
\82Æ
\82«
\81C
\82 \82È
\82½
\82Í
\83\8c\83x
\83\8b%u
\82Å
\81C
\8dÅ
\91å
\91Ì
\97Í
\82Í%d
\82Å
\82 \82Á
\82½
\81D",
1896 ends[how],u.ulevel, u.uhpmax);
1898 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1899 dump_forward_putstr(endwin, 0, "", done_stopprint);
1900 if (!done_stopprint)
1901 display_nhwindow(endwin, TRUE);
1902 if (endwin != WIN_ERR)
1903 destroy_nhwindow(endwin);
1906 /* "So when I die, the first thing I will see in Heaven is a
1908 if (have_windows && !iflags.toptenwin)
1909 exit_nhwindows((char *) 0), have_windows = FALSE;
1910 topten(how, endtime);
1912 exit_nhwindows((char *) 0);
1914 if (done_stopprint) {
1918 nh_terminate(EXIT_SUCCESS);
1922 container_contents(list, identified, all_containers, reportempty)
1924 boolean identified, all_containers, reportempty;
1926 register struct obj *box, *obj;
1928 boolean cat, dumping = iflags.in_dumplog;
1930 for (box = list; box; box = box->nobj) {
1931 if (Is_container(box) || box->otyp == STATUE) {
1932 if (!box->cknown || (identified && !box->lknown)) {
1933 box->cknown = 1; /* we're looking at the contents now */
1938 if (box->otyp == BAG_OF_TRICKS) {
1939 continue; /* wrong type of container */
1940 } else if (box->cobj) {
1941 winid tmpwin = create_nhwindow(NHW_MENU);
1942 Loot *sortedcobj, *srtc;
1945 /* at this stage, the SchroedingerBox() flag is only set
1946 if the cat inside the box is alive; the box actually
1947 contains a cat corpse that we'll pretend is not there;
1948 for dead cat, the flag will be clear and there'll be
1949 a cat corpse inside the box; either way, inventory
1950 reports the box as containing "1 item" */
1951 cat = SchroedingersBox(box);
1954 Sprintf(buf, "Contents of %s:", the(xname(box)));
1956 Sprintf(buf, "%s
\82Ì
\92\86\90g
\81F", the(xname(box)));
1957 putstr(tmpwin, 0, buf);
1959 putstr(tmpwin, 0, "");
1960 buf[0] = buf[1] = ' '; /* two leading spaces */
1961 if (box->cobj && !cat) {
1962 sortflags = (((flags.sortloot == 'l'
1963 || flags.sortloot == 'f')
1964 ? SORTLOOT_LOOT : 0)
1965 | (flags.sortpack ? SORTLOOT_PACK : 0));
1966 sortedcobj = sortloot(&box->cobj, sortflags, FALSE,
1967 (boolean FDECL((*), (OBJ_P))) 0);
1968 for (srtc = sortedcobj; ((obj = srtc->obj) != 0); ++srtc) {
1970 discover_object(obj->otyp, TRUE, FALSE);
1971 obj->known = obj->bknown = obj->dknown
1973 if (Is_container(obj) || obj->otyp == STATUE)
1974 obj->cknown = obj->lknown = 1;
1976 Strcpy(&buf[2], doname_with_price(obj));
1977 putstr(tmpwin, 0, buf);
1979 unsortloot(&sortedcobj);
1982 Strcpy(&buf[2], "Schroedinger's cat!");
1984 Strcpy(&buf[2], "
\83V
\83\85\83\8c\83f
\83B
\83\93\83K
\81[
\82Ì
\94L
\81I");
1985 putstr(tmpwin, 0, buf);
1989 display_nhwindow(tmpwin, TRUE);
1990 destroy_nhwindow(tmpwin);
1992 container_contents(box->cobj, identified, TRUE,
1994 } else if (reportempty) {
1996 pline("%s is empty.", upstart(thesimpleoname(box)));
1998 pline("%s
\82Í
\8bó
\82Á
\82Û
\82¾
\81D", xname(box));
1999 display_nhwindow(WIN_MESSAGE, FALSE);
2002 if (!all_containers)
2007 /* should be called with either EXIT_SUCCESS or EXIT_FAILURE */
2009 nh_terminate(status)
2012 program_state.in_moveloop = 0; /* won't be returning to normal play */
2014 getreturn("to exit");
2016 /* don't bother to try to release memory if we're in panic mode, to
2017 avoid trouble in case that happens to be due to memory problems */
2018 if (!program_state.panicking) {
2025 * This is liable to draw a warning if compiled with gcc, but it's
2026 * more important to flag panic() -> really_done() -> nh_terminate()
2027 * as __noreturn__ then to avoid the warning.
2029 /* don't call exit() if already executing within an exit handler;
2030 that would cancel any other pending user-mode handlers */
2031 if (program_state.exiting)
2034 program_state.exiting = 1;
2036 jputchar('\0'); /* reset terminal */
2038 nethack_exit(status);
2041 enum vanq_order_modes {
2051 NUM_VANQ_ORDER_MODES
2054 static const char *vanqorders[NUM_VANQ_ORDER_MODES] = {
2055 "traditional: by monster level, by internal monster index",
2056 "by monster toughness, by internal monster index",
2057 "alphabetically, first unique monsters, then others",
2058 "alphabetically, unique monsters and others intermixed",
2059 "by monster class, high to low level within class",
2060 "by monster class, low to high level within class",
2061 "by count, high to low, by internal index within tied count",
2062 "by count, low to high, by internal index within tied count",
2064 static int vanq_sortmode = VANQ_MLVL_MNDX;
2066 STATIC_PTR int CFDECLSPEC
2067 vanqsort_cmp(vptr1, vptr2)
2068 const genericptr vptr1;
2069 const genericptr vptr2;
2071 int indx1 = *(short *) vptr1, indx2 = *(short *) vptr2,
2072 mlev1, mlev2, mstr1, mstr2, uniq1, uniq2, died1, died2, res;
2073 const char *name1, *name2, *punct;
2076 switch (vanq_sortmode) {
2078 case VANQ_MLVL_MNDX:
2079 /* sort by monster level */
2080 mlev1 = mons[indx1].mlevel, mlev2 = mons[indx2].mlevel;
2081 res = mlev2 - mlev1; /* mlevel high to low */
2083 case VANQ_MSTR_MNDX:
2084 /* sort by monster toughness */
2085 mstr1 = mons[indx1].difficulty, mstr2 = mons[indx2].difficulty;
2086 res = mstr2 - mstr1; /* monstr high to low */
2088 case VANQ_ALPHA_SEP:
2089 uniq1 = ((mons[indx1].geno & G_UNIQ) && indx1 != PM_HIGH_PRIEST);
2090 uniq2 = ((mons[indx2].geno & G_UNIQ) && indx2 != PM_HIGH_PRIEST);
2091 if (uniq1 ^ uniq2) { /* one or other uniq, but not both */
2092 res = uniq2 - uniq1;
2094 } /* else both unique or neither unique */
2096 case VANQ_ALPHA_MIX:
2097 name1 = mons[indx1].mname, name2 = mons[indx2].mname;
2098 res = strcmpi(name1, name2); /* caseblind alhpa, low to high */
2100 case VANQ_MCLS_HTOL:
2101 case VANQ_MCLS_LTOH:
2102 /* mons[].mlet is a small integer, 1..N, of type plain char;
2103 if 'char' happens to be unsigned, (mlet1 - mlet2) would yield
2104 an inappropriate result when mlet2 is greater than mlet1,
2105 so force our copies (mcls1, mcls2) to be signed */
2106 mcls1 = (schar) mons[indx1].mlet, mcls2 = (schar) mons[indx2].mlet;
2107 /* S_ANT through S_ZRUTY correspond to lowercase monster classes,
2108 S_ANGEL through S_ZOMBIE correspond to uppercase, and various
2109 punctuation characters are used for classes beyond those */
2110 if (mcls1 > S_ZOMBIE && mcls2 > S_ZOMBIE) {
2111 /* force a specific order to the punctuation classes that's
2112 different from the internal order;
2113 internal order is ok if neither or just one is punctuation
2114 since letters have lower values so come out before punct */
2115 static const char punctclasses[] = {
2116 S_LIZARD, S_EEL, S_GOLEM, S_GHOST, S_DEMON, S_HUMAN, '\0'
2119 if ((punct = index(punctclasses, mcls1)) != 0)
2120 mcls1 = (schar) (S_ZOMBIE + 1 + (int) (punct - punctclasses));
2121 if ((punct = index(punctclasses, mcls2)) != 0)
2122 mcls2 = (schar) (S_ZOMBIE + 1 + (int) (punct - punctclasses));
2124 res = mcls1 - mcls2; /* class */
2126 mlev1 = mons[indx1].mlevel, mlev2 = mons[indx2].mlevel;
2127 res = mlev1 - mlev2; /* mlevel low to high */
2128 if (vanq_sortmode == VANQ_MCLS_HTOL)
2129 res = -res; /* mlevel high to low */
2132 case VANQ_COUNT_H_L:
2133 case VANQ_COUNT_L_H:
2134 died1 = mvitals[indx1].died, died2 = mvitals[indx2].died;
2135 res = died2 - died1; /* dead count high to low */
2136 if (vanq_sortmode == VANQ_COUNT_L_H)
2137 res = -res; /* dead count low to high */
2140 /* tiebreaker: internal mons[] index */
2142 res = indx1 - indx2; /* mndx low to high */
2146 /* returns -1 if cancelled via ESC */
2151 menu_item *selected;
2155 tmpwin = create_nhwindow(NHW_MENU);
2157 any = zeroany; /* zero out all bits */
2158 for (i = 0; i < SIZE(vanqorders); i++) {
2159 if (i == VANQ_ALPHA_MIX || i == VANQ_MCLS_HTOL) /* skip these */
2162 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, vanqorders[i],
2163 (i == vanq_sortmode) ? MENU_SELECTED : MENU_UNSELECTED);
2166 end_menu(tmpwin, "Sort order for vanquished monster counts");
2168 end_menu(tmpwin, "
\93|
\82µ
\82½
\93G
\82Ì
\83\
\81[
\83g
\8f\87");
2170 n = select_menu(tmpwin, PICK_ONE, &selected);
2171 destroy_nhwindow(tmpwin);
2173 choice = selected[0].item.a_int - 1;
2174 /* skip preselected entry if we have more than one item chosen */
2175 if (n > 1 && choice == vanq_sortmode)
2176 choice = selected[1].item.a_int - 1;
2177 free((genericptr_t) selected);
2178 vanq_sortmode = choice;
2180 return (n < 0) ? -1 : vanq_sortmode;
2183 /* #vanquished command */
2187 list_vanquished('a', FALSE);
2191 /* high priests aren't unique but are flagged as such to simplify something */
2192 #define UniqCritterIndx(mndx) ((mons[mndx].geno & G_UNIQ) \
2193 && mndx != PM_HIGH_PRIEST)
2196 list_vanquished(defquery, ask)
2202 unsigned ntypes, ni;
2203 long total_killed = 0L;
2205 short mindx[NUMMONS];
2206 char c, buf[BUFSZ], buftoo[BUFSZ];
2207 boolean dumping; /* for DUMPLOG; doesn't need to be conditional */
2209 dumping = (defquery == 'd');
2213 /* get totals first */
2215 for (i = LOW_PM; i < NUMMONS; i++) {
2216 if ((nkilled = (int) mvitals[i].died) == 0)
2218 mindx[ntypes++] = i;
2219 total_killed += (long) nkilled;
2222 /* vanquished creatures list;
2223 * includes all dead monsters, not just those killed by the player
2226 char mlet, prev_mlet = 0; /* used as small integer, not character */
2227 boolean class_header, uniq_header, was_uniq = FALSE;
2230 c = ask ? yn_function(
2231 "Do you want an account of creatures vanquished?",
2232 ynaqchars, defquery)
2235 c = ask ? yn_function(
2236 "
\93|
\82µ
\82½
\93G
\82Ì
\88ê
\97\97\82ð
\8c©
\82Ü
\82·
\82©
\81H",
2242 if (c == 'y' || c == 'a') {
2243 if (c == 'a') { /* ask player to choose sort order */
2244 /* choose value for vanq_sortmode via menu; ESC cancels list
2245 of vanquished monsters but does not set 'done_stopprint' */
2246 if (set_vanq_order() < 0)
2249 uniq_header = (vanq_sortmode == VANQ_ALPHA_SEP);
2250 class_header = (vanq_sortmode == VANQ_MCLS_LTOH
2251 || vanq_sortmode == VANQ_MCLS_HTOL);
2253 klwin = create_nhwindow(NHW_MENU);
2255 putstr(klwin, 0, "Vanquished creatures:");
2257 putstr(klwin, 0, "
\93|
\82µ
\82½
\93G
\81F");
2259 putstr(klwin, 0, "");
2261 qsort((genericptr_t) mindx, ntypes, sizeof *mindx, vanqsort_cmp);
2262 for (ni = 0; ni < ntypes; ni++) {
2264 nkilled = mvitals[i].died;
2265 mlet = mons[i].mlet;
2266 if (class_header && mlet != prev_mlet) {
2267 Strcpy(buf, def_monsyms[(int) mlet].explain);
2268 putstr(klwin, ask ? 0 : iflags.menu_headings,
2272 if (UniqCritterIndx(i)) {
2274 Sprintf(buf, "%s%s",
2275 !type_is_pname(&mons[i]) ? "the " : "",
2278 Sprintf(buf, "%s", mons[i].mname);
2284 Sprintf(eos(buf), " (twice)");
2287 Sprintf(eos(buf), " (thrice)");
2290 Sprintf(eos(buf), " (%d times)", nkilled);
2294 Sprintf(eos(buf)," (%d
\89ñ)", nkilled);
2299 if (uniq_header && was_uniq) {
2300 putstr(klwin, 0, "");
2303 /* trolls or undead might have come back,
2304 but we don't keep track of that */
2306 Strcpy(buf, an(mons[i].mname));
2309 Sprintf(buf, "%3d %s", nkilled,
2310 makeplural(mons[i].mname));
2312 Sprintf(buf, "%d
\91Ì
\82Ì%s", nkilled,
2316 /* number of leading spaces to match 3 digit prefix */
2318 pfx = !strncmpi(buf, "the ", 3) ? 0
2319 : !strncmpi(buf, "an ", 3) ? 1
2320 : !strncmpi(buf, "a ", 2) ? 2
2321 : !digit(buf[2]) ? 4 : 0;
2323 pfx = !digit(buf[2]) ? 4 : 0;
2327 Sprintf(buftoo, "%*s%s", pfx, "", buf);
2328 putstr(klwin, 0, buftoo);
2331 * if (Hallucination)
2332 * putstr(klwin, 0, "and a partridge in a pear tree");
2336 putstr(klwin, 0, "");
2338 Sprintf(buf, "%ld creatures vanquished.", total_killed);
2340 Sprintf(buf, "%ld
\95C
\82Ì
\93G
\82ð
\93|
\82µ
\82½
\81D", total_killed);
2341 putstr(klwin, 0, buf);
2343 display_nhwindow(klwin, TRUE);
2344 destroy_nhwindow(klwin);
2346 } else if (defquery == 'a') {
2347 /* #dovanquished rather than final disclosure, so pline() is ok */
2349 pline("No creatures have been vanquished.");
2351 pline("
\93|
\82µ
\82½
\93G
\82Í
\82¢
\82È
\82©
\82Á
\82½
\81D");
2353 } else if (dumping) {
2355 putstr(0, 0, "No creatures were vanquished."); /* not pline() */
2357 putstr(0, 0, "
\93|
\82µ
\82½
\93G
\82Í
\82¢
\82È
\82©
\82Á
\82½
\81D"); /* not pline() */
2363 /* number of monster species which have been genocided */
2369 for (i = LOW_PM; i < NUMMONS; ++i) {
2370 if (mvitals[i].mvflags & G_GENOD) {
2372 if (UniqCritterIndx(i))
2373 impossible("unique creature '%d: %s' genocided?",
2385 for (i = LOW_PM; i < NUMMONS; ++i) {
2386 if (UniqCritterIndx(i))
2388 if ((mvitals[i].mvflags & G_GONE) == G_EXTINCT)
2395 list_genocided(defquery, ask)
2400 int ngenocided, nextinct;
2404 boolean dumping; /* for DUMPLOG; doesn't need to be conditional */
2406 dumping = (defquery == 'd');
2410 ngenocided = num_genocides();
2411 nextinct = num_extinct();
2413 /* genocided or extinct species list */
2414 if (ngenocided != 0 || nextinct != 0) {
2416 Sprintf(buf, "Do you want a list of %sspecies%s%s?",
2417 (nextinct && !ngenocided) ? "extinct " : "",
2418 (ngenocided) ? " genocided" : "",
2419 (nextinct && ngenocided) ? " and extinct" : "");
2421 Sprintf(buf, "%s%s%s
\82µ
\82½
\8eí
\82Ì
\88ê
\97\97\82ð
\8c©
\82Ü
\82·
\82©
\81H",
2422 (nextinct && !ngenocided) ? "
\90â
\96Å" : "",
2423 (ngenocided) ? "
\8bs
\8eE" : "",
2424 (nextinct && ngenocided) ? "
\82¨
\82æ
\82Ñ
\90â
\96Å" : "");
2426 c = ask ? yn_function(buf, ynqchars, defquery) : defquery;
2430 klwin = create_nhwindow(NHW_MENU);
2432 Sprintf(buf, "%s%s species:",
2433 (ngenocided) ? "Genocided" : "Extinct",
2434 (nextinct && ngenocided) ? " or extinct" : "");
2436 Sprintf(buf, "%s%s
\82µ
\82½
\8eí:",
2437 (ngenocided) ? "
\8bs
\8eE" : "
\90â
\96Å",
2438 (nextinct && ngenocided) ? "
\82Ü
\82½
\82Í
\90â
\96Å" : "");
2440 putstr(klwin, 0, buf);
2442 putstr(klwin, 0, "");
2444 for (i = LOW_PM; i < NUMMONS; i++) {
2445 /* uniques can't be genocided but can become extinct;
2446 however, they're never reported as extinct, so skip them */
2447 if (UniqCritterIndx(i))
2449 if (mvitals[i].mvflags & G_GONE) {
2450 Sprintf(buf, " %s", makeplural(mons[i].mname));
2452 * "Extinct" is unfortunate terminology. A species
2453 * is marked extinct when its birth limit is reached,
2454 * but there might be members of the species still
2455 * alive, contradicting the meaning of the word.
2457 if ((mvitals[i].mvflags & G_GONE) == G_EXTINCT)
2459 Strcat(buf, " (extinct)");
2461 Strcat(buf, "(
\90â
\96Å)");
2462 putstr(klwin, 0, buf);
2466 putstr(klwin, 0, "");
2467 if (ngenocided > 0) {
2469 Sprintf(buf, "%d species genocided.", ngenocided);
2471 Sprintf(buf, "%d
\8eí
\97Þ
\82Ì
\8eí
\82ð
\8bs
\8eE
\82µ
\82½
\81D", ngenocided);
2472 putstr(klwin, 0, buf);
2476 Sprintf(buf, "%d species extinct.", nextinct);
2478 Sprintf(buf, "%d
\8eí
\97Þ
\82Ì
\8eí
\82ð
\90â
\96Å
\82³
\82¹
\82½
\81D", nextinct);
2479 putstr(klwin, 0, buf);
2482 display_nhwindow(klwin, TRUE);
2483 destroy_nhwindow(klwin);
2486 } else if (dumping) {
2488 putstr(0, 0, "No species were genocided or became extinct.");
2490 putstr(0, 0, "
\8bs
\8eE
\82µ
\82½
\82è
\90â
\96Å
\82³
\82¹
\82½
\82è
\82µ
\82½
\8eí
\82Í
\82¢
\82È
\82©
\82Á
\82½
\81D");
2495 /* set a delayed killer, ensure non-delayed killer is cleared out */
2497 delayed_killer(id, format, killername)
2500 const char *killername;
2502 struct kinfo *k = find_delayed_killer(id);
2505 /* no match, add a new delayed killer to the list */
2506 k = (struct kinfo *) alloc(sizeof (struct kinfo));
2507 (void) memset((genericptr_t) k, 0, sizeof (struct kinfo));
2509 k->next = killer.next;
2514 Strcpy(k->name, killername ? killername : "");
2519 find_delayed_killer(id)
2524 for (k = killer.next; k != (struct kinfo *) 0; k = k->next) {
2532 dealloc_killer(kptr)
2535 struct kinfo *prev = &killer, *k;
2537 if (kptr == (struct kinfo *) 0)
2539 for (k = killer.next; k != (struct kinfo *) 0; k = k->next) {
2545 if (k == (struct kinfo *) 0) {
2546 impossible("dealloc_killer (#%d) not on list", kptr->id);
2548 prev->next = k->next;
2549 free((genericptr_t) k);
2550 debugpline1("freed delayed killer #%d", kptr->id);
2555 save_killers(fd, mode)
2561 if (perform_bwrite(mode)) {
2562 for (kptr = &killer; kptr != (struct kinfo *) 0; kptr = kptr->next) {
2563 bwrite(fd, (genericptr_t) kptr, sizeof (struct kinfo));
2566 if (release_data(mode)) {
2567 while (killer.next) {
2568 kptr = killer.next->next;
2569 free((genericptr_t) killer.next);
2581 for (kptr = &killer; kptr != (struct kinfo *) 0; kptr = kptr->next) {
2582 mread(fd, (genericptr_t) kptr, sizeof (struct kinfo));
2584 kptr->next = (struct kinfo *) alloc(sizeof (struct kinfo));
2596 while (*p && isspace((uchar) *p))
2600 while (*p && !isspace((uchar) *p))
2612 out += strlen(out); /* eos() */
2613 while (*in && isspace((uchar) *in))
2615 while (*in && !isspace((uchar) *in))
2621 /*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*/
2623 build_english_list(in)
2627 int len = (int) strlen(p), words = wordcount(p);
2629 /* +3: " or " - " "; +(words - 1): (N-1)*(", " - " ") */
2631 len += 3 + (words - 1);
2632 out = (char *) alloc(len + 1);
2633 *out = '\0'; /* bel_copy1() appends */
2637 impossible("no words in list");
2645 /* "first or second" */
2649 /* "first, second, or third */
2653 } while (--words > 1);