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 */
805 putstr(0, 0, "Latest messages:");
806 for (i = 0, j = (int) saved_pline_index; i < DUMPLOG_MSG_COUNT;
807 ++i, j = (j + 1) % DUMPLOG_MSG_COUNT) {
808 strp = &saved_plines[j];
810 copynchars(&buf[1], *strp, BUFSZ - 1 - 1);
812 #ifdef FREE_ALL_MEMORY
813 free(*strp), *strp = 0;
822 dump_everything(how, when)
824 time_t when; /* date+time at end of game */
827 char pbuf[BUFSZ], datetimebuf[24]; /* [24]: room for 64-bit bogus value */
830 if (!iflags.in_dumplog)
833 init_symbols(); /* revert to default symbol set */
835 /* one line version ID, which includes build date+time;
836 it's conceivable that the game started with a different
837 build date+time or even with an older nethack version,
838 but we only have access to the one it finished under */
839 putstr(0, 0, getversionstring(pbuf));
842 /* game start and end date+time to disambiguate version date+time */
843 Strcpy(datetimebuf, yyyymmddhhmmss(ubirthday));
844 Sprintf(pbuf, "Game began %4.4s-%2.2s-%2.2s %2.2s:%2.2s:%2.2s",
845 &datetimebuf[0], &datetimebuf[4], &datetimebuf[6],
846 &datetimebuf[8], &datetimebuf[10], &datetimebuf[12]);
847 Strcpy(datetimebuf, yyyymmddhhmmss(when));
848 Sprintf(eos(pbuf), ", ended %4.4s-%2.2s-%2.2s %2.2s:%2.2s:%2.2s.",
849 &datetimebuf[0], &datetimebuf[4], &datetimebuf[6],
850 &datetimebuf[8], &datetimebuf[10], &datetimebuf[12]);
854 /* character name and basic role info */
855 Sprintf(pbuf, "%s, %s %s %s %s", plname,
856 aligns[1 - u.ualign.type].adj,
857 genders[flags.female].adj,
859 (flags.female && urole.name.f) ? urole.name.f : urole.name.m);
864 putstr(0, 0, do_statusline1());
865 putstr(0, 0, do_statusline2());
870 putstr(0, 0, "Inventory:");
871 (void) display_inventory((char *) 0, TRUE);
872 container_contents(invent, TRUE, TRUE, FALSE);
873 enlightenment((BASICENLIGHTENMENT | MAGICENLIGHTENMENT),
874 (how >= PANICKED) ? ENL_GAMEOVERALIVE : ENL_GAMEOVERDEAD);
876 list_vanquished('d', FALSE); /* 'd' => 'y' */
878 list_genocided('d', FALSE); /* 'd' => 'y' */
880 show_conduct((how >= PANICKED) ? 1 : 2);
882 show_overview((how >= PANICKED) ? 1 : 2, how);
884 dump_redirect(FALSE);
896 char c = '\0', defquery;
900 if (invent && !done_stopprint) {
903 Sprintf(qbuf, "Do you want to see what you had when you %s?",
904 (how == QUIT) ? "quit" : "died");
906 Sprintf(qbuf,"%s
\82Æ
\82«
\89½
\82ð
\8e\9d\82Á
\82Ä
\82¢
\82½
\82©
\8c©
\82Ü
\82·
\82©
\81H",
907 (how == QUIT) ? "
\82â
\82ß
\82½" : "
\8e\80\82ñ
\82¾");
911 Strcpy(qbuf, "Do you want your possessions identified?");
913 Strcpy(qbuf,"
\8e\9d\82¿
\95¨
\82ð
\8e¯
\95Ê
\82µ
\82Ü
\82·
\82©
\81H");
915 ask = should_query_disclose_option('i', &defquery);
916 c = ask ? yn_function(qbuf, ynqchars, defquery) : defquery;
918 /* caller has already ID'd everything */
919 (void) display_inventory((char *) 0, TRUE);
920 container_contents(invent, TRUE, TRUE, FALSE);
926 if (!done_stopprint) {
927 ask = should_query_disclose_option('a', &defquery);
929 c = ask ? yn_function("Do you want to see your attributes?", ynqchars,
933 c = ask ? yn_function("
\91®
\90«
\82ð
\8c©
\82Ü
\82·
\82©
\81H", ynqchars,
938 enlightenment((BASICENLIGHTENMENT | MAGICENLIGHTENMENT),
939 (how >= PANICKED) ? ENL_GAMEOVERALIVE
945 if (!done_stopprint) {
946 ask = should_query_disclose_option('v', &defquery);
947 list_vanquished(defquery, ask);
950 if (!done_stopprint) {
951 ask = should_query_disclose_option('g', &defquery);
952 list_genocided(defquery, ask);
955 if (!done_stopprint) {
956 ask = should_query_disclose_option('c', &defquery);
958 c = ask ? yn_function("Do you want to see your conduct?", ynqchars,
962 c = ask ? yn_function("
\82Ç
\82¤
\82¢
\82¤
\8ds
\93®
\82ð
\82Æ
\82Á
\82½
\82©
\8c©
\82Ü
\82·
\82©
\81H", ynqchars,
967 show_conduct((how >= PANICKED) ? 1 : 2);
972 if (!done_stopprint) {
973 ask = should_query_disclose_option('o', &defquery);
975 c = ask ? yn_function("Do you want to see the dungeon overview?",
979 c = ask ? yn_function("
\96À
\8b{
\82Ì
\8aT
\97v
\82ð
\8c©
\82Ü
\82·
\82©
\81H",
984 show_overview((how >= PANICKED) ? 1 : 2, how);
990 /* try to get the player back in a viable state after being killed */
995 int uhpmin = max(2 * u.ulevel, 10);
997 if (u.uhpmax < uhpmin)
1000 if (Upolyd) /* Unchanging, or death which bypasses losing hit points */
1002 if (u.uhunger < 500 || how == CHOKING) {
1005 /* cure impending doom of sickness hero won't have time to fix */
1006 if ((Sick & TIMEOUT) == 1L) {
1007 make_sick(0L, (char *) 0, FALSE, SICK_ALL);
1010 nomovemsg = "You survived that attempt on your life.";
1012 nomovemsg = "
\82 \82È
\82½
\82Í
\90¶
\82«
\82È
\82ª
\82ç
\82¦
\82½
\81D";
1018 if (u.utrap && u.utraptype == TT_LAVA)
1021 u.ugrave_arise = NON_PM;
1024 if (!context.mon_moving)
1025 endmultishot(FALSE);
1027 /* might drop hero onto a trap that kills her all over again */
1028 expels(u.ustuck, u.ustuck->data, TRUE);
1029 } else if (u.ustuck) {
1030 if (Upolyd && sticks(youmonst.data))
1031 You("release %s.", mon_nam(u.ustuck));
1033 pline("%s releases you.", Monnam(u.ustuck));
1039 * Get valuables from the given list. Revised code: the list always remains
1044 struct obj *list; /* inventory or container contents */
1046 register struct obj *obj;
1049 /* find amulets and gems, ignoring all artifacts */
1050 for (obj = list; obj; obj = obj->nobj)
1051 if (Has_contents(obj)) {
1052 get_valuables(obj->cobj);
1053 } else if (obj->oartifact) {
1055 } else if (obj->oclass == AMULET_CLASS) {
1056 i = obj->otyp - FIRST_AMULET;
1057 if (!amulets[i].count) {
1058 amulets[i].count = obj->quan;
1059 amulets[i].typ = obj->otyp;
1061 amulets[i].count += obj->quan; /* always adds one */
1062 } else if (obj->oclass == GEM_CLASS && obj->otyp < LUCKSTONE) {
1063 i = min(obj->otyp, LAST_GEM + 1) - FIRST_GEM;
1064 if (!gems[i].count) {
1065 gems[i].count = obj->quan;
1066 gems[i].typ = obj->otyp;
1068 gems[i].count += obj->quan;
1074 * Sort collected valuables, most frequent to least. We could just
1075 * as easily use qsort, but we don't care about efficiency here.
1078 sort_valuables(list, size)
1079 struct valuable_data list[];
1080 int size; /* max value is less than 20 */
1083 struct valuable_data ltmp;
1085 /* move greater quantities to the front of the list */
1086 for (i = 1; i < size; i++) {
1087 if (list[i].count == 0)
1088 continue; /* empty slot */
1089 ltmp = list[i]; /* structure copy */
1090 for (j = i; j > 0; --j)
1091 if (list[j - 1].count >= ltmp.count)
1094 list[j] = list[j - 1];
1103 * odds_and_ends() was used for 3.6.0 and 3.6.1.
1104 * Schroedinger's Cat is handled differently as of 3.6.2.
1106 STATIC_DCL boolean FDECL(odds_and_ends, (struct obj *, int));
1111 odds_and_ends(list, what)
1117 for (otmp = list; otmp; otmp = otmp->nobj) {
1119 case CAT_CHECK: /* Schroedinger's Cat */
1120 /* Ascending is deterministic */
1121 if (SchroedingersBox(otmp))
1125 if (Has_contents(otmp))
1126 return odds_and_ends(otmp->cobj, what);
1132 /* deal with some objects which may be in an abnormal state at end of game */
1134 done_object_cleanup()
1138 /* might have been killed while using a disposable item, so make sure
1139 it's gone prior to inventory disclosure and creation of bones */
1142 * Hero can die when throwing an object (by hitting an adjacent
1143 * gas spore, for instance, or being hit by mis-returning Mjollnir),
1144 * or while in transit (from falling down stairs). If that happens,
1145 * some object(s) might be in limbo rather than on the map or in
1146 * any inventory. Saving bones with an active light source in limbo
1147 * would trigger an 'object not local' panic.
1149 * We used to use dealloc_obj() on thrownobj and kickedobj but
1150 * that keeps them out of bones and could leave uball in a confused
1151 * state (gone but still attached). Place them on the map but
1152 * bypass flooreffects(). That could lead to minor anomalies in
1153 * bones, like undamaged paper at water or lava locations or piles
1154 * not being knocked down holes, but it seems better to get this
1155 * game over with than risk being tangled up in more and more details.
1157 ox = u.ux + u.dx, oy = u.uy + u.dy;
1158 if (!isok(ox, oy) || !accessible(ox, oy))
1159 ox = u.ux, oy = u.uy;
1160 /* put thrown or kicked object on map (for bones); location might
1161 be incorrect (perhaps killed by divine lightning when throwing at
1162 a temple priest?) but this should be better than just vanishing
1163 (fragile stuff should be taken care of before getting here) */
1164 if (thrownobj && thrownobj->where == OBJ_FREE) {
1165 place_object(thrownobj, ox, oy);
1166 stackobj(thrownobj), thrownobj = 0;
1168 if (kickedobj && kickedobj->where == OBJ_FREE) {
1169 place_object(kickedobj, ox, oy);
1170 stackobj(kickedobj), kickedobj = 0;
1172 /* if Punished hero dies during level change or dies or quits while
1173 swallowed, uball and uchain will be in limbo; put them on floor
1174 so bones will have them and object list cleanup finds them */
1175 if (uchain && uchain->where == OBJ_FREE) {
1177 lift_covet_and_placebc(override_restriction);
1179 /* persistent inventory window now obsolete since disclosure uses
1180 a normal popup one; avoids "Bad fruit #n" when saving bones */
1181 if (iflags.perm_invent) {
1182 iflags.perm_invent = FALSE;
1183 update_inventory(); /* make interface notice the change */
1188 /* called twice; first to calculate total, then to list relevant items */
1190 artifact_score(list, counting, endwin)
1192 boolean counting; /* true => add up points; false => display them */
1198 short dummy; /* object type returned by artifact_name() */
1200 for (otmp = list; otmp; otmp = otmp->nobj) {
1201 if (otmp->oartifact || otmp->otyp == BELL_OF_OPENING
1202 || otmp->otyp == SPE_BOOK_OF_THE_DEAD
1203 || otmp->otyp == CANDELABRUM_OF_INVOCATION) {
1204 value = arti_cost(otmp); /* zorkmid value */
1205 points = value * 5 / 2; /* score value */
1207 nowrap_add(u.urexp, points);
1209 discover_object(otmp->otyp, TRUE, FALSE);
1210 otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
1211 /* assumes artifacts don't have quan > 1 */
1213 Sprintf(pbuf, "%s%s (worth %ld %s and %ld points)",
1214 the_unique_obj(otmp) ? "The " : "",
1215 otmp->oartifact ? artifact_name(xname(otmp), &dummy)
1216 : OBJ_NAME(objects[otmp->otyp]),
1217 value, currency(value), points);
1219 Sprintf(pbuf, "%s(%ld%s
\81C%ld
\83|
\83C
\83\93\83g
\82Ì
\89¿
\92l)
\81C",
1220 otmp->oartifact ? artifact_name(xname(otmp), &dummy)
1221 : OBJ_NAME(objects[otmp->otyp]),
1222 value, currency(value), points);
1224 putstr(endwin, 0, pbuf);
1227 if (Has_contents(otmp))
1228 artifact_score(otmp->cobj, counting, endwin);
1232 /* Be careful not to call panic from here! */
1237 boolean survive = FALSE;
1239 if (how == TRICKED) {
1240 if (killer.name[0]) {
1241 paniclog("trickery", killer.name);
1242 killer.name[0] = '\0';
1246 You("are a very tricky wizard, it seems.");
1248 You("
\82Æ
\82Ä
\82à
\88µ
\82¢
\82É
\82
\82¢wizard
\82Ì
\82æ
\82¤
\82¾
\81D");
1249 killer.format = KILLED_BY_AN; /* reset to 0 */
1253 if (program_state.panicking
1254 #ifdef HANGUPHANDLING
1255 || program_state.done_hup
1258 /* skip status update if panicking or disconnected */
1259 context.botl = context.botlx = iflags.time_botl = FALSE;
1261 /* otherwise force full status update */
1262 context.botlx = TRUE;
1266 if (iflags.debug_fuzzer) {
1267 if (!(program_state.panicking || how == PANICKED)) {
1269 /* periodically restore characteristics and lost exp levels
1270 or cure lycanthropy */
1272 struct obj *potion = mksobj((u.ulycn > LOW_PM && !rn2(3))
1273 ? POT_WATER : POT_RESTORE_ABILITY,
1277 (void) peffects(potion); /* always -1 for restore ability */
1278 /* not useup(); we haven't put this potion into inventory */
1279 obfree(potion, (struct obj *) 0);
1281 killer.name[0] = '\0';
1286 if (how == ASCENDED || (!killer.name[0] && how == GENOCIDED))
1287 killer.format = NO_KILLER_PREFIX;
1288 /* Avoid killed by "a" burning or "a" starvation */
1289 if (!killer.name[0] && (how == STARVING || how == BURNING))
1290 killer.format = KILLED_BY;
1291 if (!killer.name[0] || how >= PANICKED)
1293 Strcpy(killer.name, deaths[how]);
1295 Strcpy(killer.name, ends[how]);
1297 if (how < PANICKED) {
1299 /* in case caller hasn't already done this */
1300 if (u.uhp != 0 || (Upolyd && u.mh != 0)) {
1301 /* force HP to zero in case it is still positive (some
1302 deaths aren't triggered by loss of hit points), or
1303 negative (-1 is used as a flag in some circumstances
1304 which don't apply when actually dying due to HP loss) */
1309 if (Lifesaved && (how <= GENOCIDED)) {
1311 pline("But wait...");
1313 pline("
\82¿
\82å
\82Á
\82Æ
\82Ü
\82Á
\82½
\81D
\81D
\81D");
1314 makeknown(AMULET_OF_LIFE_SAVING);
1316 Your("medallion %s!", !Blind ? "begins to glow" : "feels warm");
1318 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½");
1323 You("
\93f
\82¢
\82½
\81D
\81D
\81D");
1325 You_feel("much better!");
1327 You("
\8bC
\95ª
\82ª
\82æ
\82
\82È
\82Á
\82½
\81I");
1329 pline_The("medallion crumbles to dust!");
1331 pline("
\96\82\8f\9c\82¯
\82Í
\82±
\82È
\82²
\82È
\82É
\82
\82¾
\82¯
\82½
\81I");
1335 (void) adjattrib(A_CON, -1, TRUE);
1337 if (how == GENOCIDED) {
1339 pline("Unfortunately you are still genocided...");
1341 pline("
\8ec
\94O
\82È
\82ª
\82ç
\81C
\82 \82È
\82½
\82Í
\8bs
\8eE
\82³
\82ê
\82½
\82Ü
\82Ü
\82¾
\81D
\81D
\81D");
1346 /* explore and wizard modes offer player the option to keep playing */
1348 if (!survive && (wizard || discover) && how <= GENOCIDED
1349 && !paranoid_query(ParanoidDie, "Die?")) {
1351 if (!survive && (wizard || discover) && how <= GENOCIDED
1352 && !paranoid_query(ParanoidDie, "
\8e\80\82ñ
\82Å
\82Ý
\82é
\81H")) {
1355 pline("OK, so you don't %s.", (how == CHOKING) ? "choke" : "die");
1357 You("
\8e\80\82È
\82È
\82©
\82Á
\82½
\81D");
1358 iflags.last_msg = PLNMSG_OK_DONT_DIE;
1364 killer.name[0] = '\0';
1365 killer.format = KILLED_BY_AN; /* reset to 0 */
1372 /* separated from done() in order to specify the __noreturn__ attribute */
1379 winid endwin = WIN_ERR;
1380 boolean bones_ok, have_windows = iflags.window_inited;
1381 struct obj *corpse = (struct obj *) 0;
1387 * The game is now over...
1389 program_state.gameover = 1;
1390 /* in case of a subsequent panic(), there's no point trying to save */
1391 program_state.something_worth_saving = 0;
1392 #ifdef HANGUPHANDLING
1393 if (program_state.done_hup)
1396 /* render vision subsystem inoperative */
1397 iflags.vision_inited = 0;
1399 /* maybe use up active invent item(s), place thrown/kicked missile,
1400 deal with ball and chain possibly being temporarily off the map */
1401 if (!program_state.panicking)
1402 done_object_cleanup();
1403 /* in case we're panicking; normally cleared by done_object_cleanup() */
1404 iflags.perm_invent = FALSE;
1406 /* remember time of death here instead of having bones, rip, and
1407 topten figure it out separately and possibly getting different
1408 time or even day if player is slow responding to --More-- */
1409 urealtime.finish_time = endtime = getnow();
1410 urealtime.realtime += (long) (endtime - urealtime.start_timing);
1411 /* collect these for end of game disclosure (not used during play) */
1412 iflags.at_night = night();
1413 iflags.at_midnight = midnight();
1415 dump_open_log(endtime);
1416 /* Sometimes you die on the first move. Life's not fair.
1417 * On those rare occasions you get hosed immediately, go out
1418 * smiling... :-) -3.
1420 if (moves <= 1 && how < PANICKED && !done_stopprint)
1422 pline("Do not pass Go. Do not collect 200 %s.", currency(200L));
1424 pline("
\92\8d\88Ó
\88ê
\95b
\81C
\89ö
\89ä
\88ê
\90¶
\81C
\8e\80\96S
\88ê
\95à
\81D");
1427 wait_synch(); /* flush screen output */
1429 (void) signal(SIGINT, (SIG_RET_TYPE) done_intr);
1430 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
1431 (void) signal(SIGQUIT, (SIG_RET_TYPE) done_intr);
1432 sethanguphandler(done_hangup);
1434 #endif /* NO_SIGNAL */
1436 bones_ok = (how < GENOCIDED) && can_make_bones();
1438 if (bones_ok && launch_in_progress())
1439 force_launch_placement();
1441 /* maintain ugrave_arise even for !bones_ok */
1442 if (how == PANICKED)
1443 u.ugrave_arise = (NON_PM - 3); /* no corpse, no grave */
1444 else if (how == BURNING || how == DISSOLVED) /* corpse burns up too */
1445 u.ugrave_arise = (NON_PM - 2); /* leave no corpse */
1446 else if (how == STONING)
1447 u.ugrave_arise = (NON_PM - 1); /* statue instead of corpse */
1448 else if (how == TURNED_SLIME
1449 /* it's possible to turn into slime even though green slimes
1450 have been genocided: genocide could occur after hero is
1451 already infected or hero could eat a glob of one created
1452 before genocide; don't try to arise as one if they're gone */
1453 && !(mvitals[PM_GREEN_SLIME].mvflags & G_GENOD))
1454 u.ugrave_arise = PM_GREEN_SLIME;
1457 killer.format = NO_KILLER_PREFIX;
1460 u.umortality++; /* skipped above when how==QUIT */
1462 Strcpy(killer.name, "quit while already on Charon's boat");
1464 Strcpy(killer.name, "
\8eO
\93r
\82Ì
\90ì
\82Ì
\93n
\82µ
\91D
\82É
\8fæ
\82Á
\82Ä
\82¢
\82é
\8aÔ
\82É
\94²
\82¯
\82½");
1467 if (how == ESCAPED || how == PANICKED)
1468 killer.format = NO_KILLER_PREFIX;
1470 #if 0 /*JP*//*
\93ú
\96{
\8cê
\82Å
\82Í
\8eg
\82í
\82È
\82¢*/
1471 fixup_death(how); /* actually, fixup multi_reason */
1474 if (how != PANICKED) {
1475 boolean silently = done_stopprint ? TRUE : FALSE;
1477 /* these affect score and/or bones, but avoid them during panic */
1478 taken = paybill((how == ESCAPED) ? -1 : (how != QUIT), silently);
1482 taken = FALSE; /* lint; assert( !bones_ok ); */
1487 display_nhwindow(WIN_MESSAGE, FALSE);
1489 if (how != PANICKED) {
1493 * This is needed for both inventory disclosure and dumplog.
1494 * Both are optional, so do it once here instead of duplicating
1495 * it in both of those places.
1497 for (obj = invent; obj; obj = obj->nobj) {
1498 discover_object(obj->otyp, TRUE, FALSE);
1499 obj->known = obj->bknown = obj->dknown = obj->rknown = 1;
1500 if (Is_container(obj) || obj->otyp == STATUE)
1501 obj->cknown = obj->lknown = 1;
1502 /* we resolve Schroedinger's cat now in case of both
1503 disclosure and dumplog, where the 50:50 chance for
1504 live cat has to be the same both times */
1505 if (SchroedingersBox(obj)) {
1506 if (!Schroedingers_cat) {
1507 /* tell observe_quantum_cat() not to create a cat; if it
1508 chooses live cat in this situation, it will leave the
1509 SchroedingersBox flag set (for container_contents()) */
1510 observe_quantum_cat(obj, FALSE, FALSE);
1511 if (SchroedingersBox(obj))
1512 Schroedingers_cat = TRUE;
1514 obj->spe = 0; /* ordinary box with cat corpse in it */
1518 if (strcmp(flags.end_disclose, "none"))
1519 disclose(how, taken);
1521 dump_everything(how, endtime);
1524 /* if pets will contribute to score, populate mydogs list now
1525 (bones creation isn't a factor, but pline() messaging is; used to
1526 be done even sooner, but we need it to come after dump_everything()
1527 so that any accompanying pets are still on the map during dump) */
1528 if (how == ESCAPED || how == ASCENDED)
1531 /* finish_paybill should be called after disclosure but before bones */
1532 if (bones_ok && taken)
1535 /* grave creation should be after disclosure so it doesn't have
1536 this grave in the current level's features for #overview */
1537 if (bones_ok && u.ugrave_arise == NON_PM
1538 && !(mvitals[u.umonnum].mvflags & G_NOCORPSE)) {
1539 int mnum = u.umonnum;
1542 /* Base corpse on race when not poly'd since original u.umonnum
1543 is based on role, and all role monsters are human. */
1544 mnum = (flags.female && urace.femalenum != NON_PM)
1548 corpse = mk_named_object(CORPSE, &mons[mnum], u.ux, u.uy, plname);
1550 Sprintf(pbuf, "%s, ", plname);
1552 Sprintf(pbuf, "%s
\82Ì
\95æ
\81C", plname);
1553 formatkiller(eos(pbuf), sizeof pbuf - strlen(pbuf), how, TRUE);
1554 make_grave(u.ux, u.uy, pbuf);
1556 pbuf[0] = '\0'; /* clear grave text; also lint suppression */
1558 /* calculate score, before creating bones [container gold] */
1560 int deepest = deepest_lev_reached(FALSE);
1562 umoney = money_cnt(invent);
1564 umoney += hidden_gold(); /* accumulate gold from containers */
1565 tmp = umoney - tmp; /* net gain */
1571 tmp += 50L * (long) (deepest - 1);
1573 tmp += 1000L * (long) ((deepest > 30) ? 10 : deepest - 20);
1574 nowrap_add(u.urexp, tmp);
1576 /* ascension gives a score bonus iff offering to original deity */
1577 if (how == ASCENDED && u.ualign.type == u.ualignbase[A_ORIGINAL]) {
1578 /* retaining original alignment: score *= 2;
1579 converting, then using helm-of-OA to switch back: *= 1.5 */
1580 tmp = (u.ualignbase[A_CURRENT] == u.ualignbase[A_ORIGINAL])
1583 nowrap_add(u.urexp, tmp);
1587 if (u.ugrave_arise >= LOW_PM && !done_stopprint) {
1588 /* give this feedback even if bones aren't going to be created,
1589 so that its presence or absence doesn't tip off the player to
1590 new bones or their lack; it might be a lie if makemon fails */
1593 (u.ugrave_arise != PM_GREEN_SLIME)
1594 ? "body rises from the dead"
1595 : "revenant persists",
1596 an(mons[u.ugrave_arise].mname));
1598 Your("%s as %s
\82É
\82È
\82Á
\82½
\81D
\81D
\81D",
1599 (u.ugrave_arise != PM_GREEN_SLIME)
1600 ? "
\91Ì
\82Í
\8e\80\91Ì
\82©
\82ç
\91h
\82Á
\82Ä"
1602 mons[u.ugrave_arise].mname);
1604 display_nhwindow(WIN_MESSAGE, FALSE);
1609 if (!wizard || paranoid_query(ParanoidBones, "Save bones?"))
1611 if (!wizard || paranoid_query(ParanoidBones, "
\8d\9c\82ð
\82¤
\82ß
\82é
\81H"))
1612 savebones(how, endtime, corpse);
1613 /* corpse may be invalid pointer now so
1614 ensure that it isn't used again */
1615 corpse = (struct obj *) 0;
1618 /* update gold for the rip output, which can't use hidden_gold()
1619 (containers will be gone by then if bones just got saved...) */
1620 done_money = umoney;
1622 /* clean up unneeded windows */
1625 free_pickinv_cache(); /* extra persistent window if perm_invent */
1626 if (WIN_INVEN != WIN_ERR) {
1627 destroy_nhwindow(WIN_INVEN), WIN_INVEN = WIN_ERR;
1628 /* precaution in case any late update_inventory() calls occur */
1629 iflags.perm_invent = 0;
1631 display_nhwindow(WIN_MESSAGE, TRUE);
1632 destroy_nhwindow(WIN_MAP), WIN_MAP = WIN_ERR;
1633 if (WIN_STATUS != WIN_ERR)
1634 destroy_nhwindow(WIN_STATUS), WIN_STATUS = WIN_ERR;
1635 destroy_nhwindow(WIN_MESSAGE), WIN_MESSAGE = WIN_ERR;
1637 if (!done_stopprint || flags.tombstone)
1638 endwin = create_nhwindow(NHW_TEXT);
1640 if (how < GENOCIDED && flags.tombstone && endwin != WIN_ERR)
1641 outrip(endwin, how, endtime);
1643 done_stopprint = 1; /* just avoid any more output */
1646 /* 'how' reasons beyond genocide shouldn't show tombstone;
1647 for normal end of game, genocide doesn't either */
1648 if (how <= GENOCIDED) {
1649 dump_redirect(TRUE);
1650 if (iflags.in_dumplog)
1651 genl_outrip(0, how, endtime);
1652 dump_redirect(FALSE);
1655 if (u.uhave.amulet) {
1657 Strcat(killer.name, " (with the Amulet)");
1659 Strcat(killer.name, "
\96\82\8f\9c\82¯
\82ð
\8eè
\82É");
1660 } else if (how == ESCAPED) {
1661 if (Is_astralevel(&u.uz)) /* offered Amulet to wrong deity */
1663 Strcat(killer.name, " (in celestial disgrace)");
1665 Strcat(killer.name, "
\93V
\8fã
\82Å
\92p
\90J
\82ð
\8eó
\82¯
\92E
\8fo
\82µ
\82½");
1666 else if (carrying(FAKE_AMULET_OF_YENDOR))
1668 Strcat(killer.name, " (with a fake Amulet)");
1670 Strcat(killer.name, "
\8bU
\95¨
\82Ì
\96\82\8f\9c\82¯
\82ð
\92Í
\82Ü
\82³
\82ê
\92E
\8fo
\82µ
\82½");
1671 /* don't bother counting to see whether it should be plural */
1675 Sprintf(pbuf, "%s %s the %s...", Goodbye(), plname,
1677 ? (const char *) ((flags.female && urole.name.f)
1680 : (const char *) (flags.female ? "Demigoddess" : "Demigod"));
1682 Sprintf(pbuf, "%s%s
\82Ì%s
\81D
\81D
\81D", Goodbye(),
1684 ? (const char *) ((flags.female && urole.name.f)
1687 : (const char *) (flags.female ? "
\8f\97\90_" : "
\90_"),
1690 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1691 dump_forward_putstr(endwin, 0, "", done_stopprint);
1693 if (how == ESCAPED || how == ASCENDED) {
1696 register struct val_list *val;
1699 for (val = valuables; val->list; val++)
1700 for (i = 0; i < val->size; i++) {
1701 val->list[i].count = 0L;
1703 get_valuables(invent);
1705 /* add points for collected valuables */
1706 for (val = valuables; val->list; val++)
1707 for (i = 0; i < val->size; i++)
1708 if (val->list[i].count != 0L) {
1709 tmp = val->list[i].count
1710 * (long) objects[val->list[i].typ].oc_cost;
1711 nowrap_add(u.urexp, tmp);
1714 /* count the points for artifacts */
1715 artifact_score(invent, TRUE, endwin);
1717 viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */
1720 Strcpy(pbuf, "You");
1722 Strcpy(pbuf, "
\82 \82È
\82½");
1723 if (mtmp || Schroedingers_cat) {
1726 Sprintf(eos(pbuf), " and %s", mon_nam(mtmp));
1728 Sprintf(eos(pbuf), "
\82Æ%s", mon_nam(mtmp));
1730 nowrap_add(u.urexp, mtmp->mhp);
1733 /* [it might be more robust to create a housecat and add it to
1734 mydogs; it doesn't have to be placed on the map for that] */
1735 if (Schroedingers_cat) {
1736 int mhp, m_lev = adj_lev(&mons[PM_HOUSECAT]);
1739 nowrap_add(u.urexp, mhp);
1741 Strcat(eos(pbuf), " and Schroedinger's cat");
1743 Strcat(eos(pbuf), "
\82Æ
\83V
\83\85\83\8c\83f
\83B
\83\93\83K
\81[
\82Ì
\94L");
1746 if (!done_stopprint)
1747 Strcat(pbuf, "
\82Í");
1749 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1755 Strcat(pbuf, "
\82Í");
1758 Sprintf(eos(pbuf), "%s with %ld point%s,",
1759 how == ASCENDED ? "went to your reward"
1760 : "escaped from the dungeon",
1761 u.urexp, plur(u.urexp));
1763 Sprintf(eos(pbuf), "%ld
\83|
\83C
\83\93\83g
\83}
\81[
\83N
\82µ%s
\81D",
1765 how==ASCENDED ? "
\8f¸
\93V
\82µ
\82½" : "
\96À
\8b{
\82©
\82ç
\92E
\8fo
\82µ
\82½");
1767 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1769 if (!done_stopprint)
1770 artifact_score(invent, FALSE, endwin); /* list artifacts */
1772 dump_redirect(TRUE);
1773 if (iflags.in_dumplog)
1774 artifact_score(invent, FALSE, 0);
1775 dump_redirect(FALSE);
1778 /* list valuables here */
1779 for (val = valuables; val->list; val++) {
1780 sort_valuables(val->list, val->size);
1781 for (i = 0; i < val->size && !done_stopprint; i++) {
1782 int typ = val->list[i].typ;
1783 long count = val->list[i].count;
1787 if (objects[typ].oc_class != GEM_CLASS || typ <= LAST_GEM) {
1788 otmp = mksobj(typ, FALSE, FALSE);
1789 discover_object(otmp->otyp, TRUE, FALSE);
1790 otmp->known = 1; /* for fake amulets */
1791 otmp->dknown = 1; /* seen it (blindness fix) */
1792 if (has_oname(otmp))
1796 Sprintf(pbuf, "%8ld %s (worth %ld %s),", count,
1797 xname(otmp), count * (long) objects[typ].oc_cost,
1800 Sprintf(pbuf, "%ld
\8cÂ
\82Ì%s(%ld%s
\82Ì
\89¿
\92l)
\81C", count,
1801 xname(otmp), count * (long) objects[typ].oc_cost,
1804 obfree(otmp, (struct obj *) 0);
1807 Sprintf(pbuf, "%8ld worthless piece%s of colored glass,",
1808 count, plur(count));
1810 Sprintf(pbuf, "%ld
\8cÂ
\82Ì
\89¿
\92l
\82Ì
\82È
\82¢
\90F
\82Â
\82«
\83K
\83\89\83X
\81C",
1814 dump_forward_putstr(endwin, 0, pbuf, 0);
1819 /* did not escape or ascend */
1820 if (u.uz.dnum == 0 && u.uz.dlevel <= 0) {
1821 /* level teleported out of the dungeon; `how' is DIED,
1822 due to falling or to "arriving at heaven prematurely" */
1824 Sprintf(pbuf, "You %s beyond the confines of the dungeon",
1825 (u.uz.dlevel < 0) ? "passed away" : ends[how]);
1827 Sprintf(pbuf, "
\96À
\8b{
\82Ì
\97Ì
\88æ
\82ð
\89z
\82¦%s
\81D",
1828 (u.uz.dlevel < 0) ? "
\8fÁ
\82¦
\82³
\82Á
\82½" : ends[how]);
1831 /* more conventional demise */
1832 const char *where = dungeons[u.uz.dnum].dname;
1834 if (Is_astralevel(&u.uz))
1836 where = "The Astral Plane";
1838 where = "
\90¸
\97ì
\8aE
\82É
\82Ä";
1840 Sprintf(pbuf, "You %s in %s", ends[how], where);
1842 Sprintf(pbuf, "
\82 \82È
\82½
\82Í%s", where);
1843 if (!In_endgame(&u.uz) && !Is_knox(&u.uz))
1845 Sprintf(eos(pbuf), " on dungeon level %d",
1846 In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz));
1848 Sprintf(eos(pbuf), "
\82Ì
\92n
\89º%d
\8aK
\82Å",
1849 In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz));
1854 Sprintf(eos(pbuf), " with %ld point%s,", u.urexp, plur(u.urexp));
1856 Sprintf(eos(pbuf), " %ld
\83|
\83C
\83\93\83g
\82ð
\83}
\81[
\83N
\82µ
\81C", u.urexp);
1857 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1861 Sprintf(pbuf, "and %ld piece%s of gold, after %ld move%s.", umoney,
1862 plur(umoney), moves, plur(moves));
1864 Sprintf(pbuf, "%ld
\96\87\82Ì
\8bà
\89Ý
\82ð
\8e\9d\82Á
\82Ä
\81C%ld
\95à
\93®
\82¢
\82½
\81D", umoney,
1867 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1870 "You were level %d with a maximum of %d hit point%s when you %s.",
1871 u.ulevel, u.uhpmax, plur(u.uhpmax), ends[how]);
1874 "%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",
1875 ends[how],u.ulevel, u.uhpmax);
1877 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1878 dump_forward_putstr(endwin, 0, "", done_stopprint);
1879 if (!done_stopprint)
1880 display_nhwindow(endwin, TRUE);
1881 if (endwin != WIN_ERR)
1882 destroy_nhwindow(endwin);
1885 /* "So when I die, the first thing I will see in Heaven is a
1887 if (have_windows && !iflags.toptenwin)
1888 exit_nhwindows((char *) 0), have_windows = FALSE;
1889 topten(how, endtime);
1891 exit_nhwindows((char *) 0);
1893 if (done_stopprint) {
1897 nh_terminate(EXIT_SUCCESS);
1901 container_contents(list, identified, all_containers, reportempty)
1903 boolean identified, all_containers, reportempty;
1905 register struct obj *box, *obj;
1907 boolean cat, dumping = iflags.in_dumplog;
1909 for (box = list; box; box = box->nobj) {
1910 if (Is_container(box) || box->otyp == STATUE) {
1911 if (!box->cknown || (identified && !box->lknown)) {
1912 box->cknown = 1; /* we're looking at the contents now */
1917 if (box->otyp == BAG_OF_TRICKS) {
1918 continue; /* wrong type of container */
1919 } else if (box->cobj) {
1920 winid tmpwin = create_nhwindow(NHW_MENU);
1921 Loot *sortedcobj, *srtc;
1924 /* at this stage, the SchroedingerBox() flag is only set
1925 if the cat inside the box is alive; the box actually
1926 contains a cat corpse that we'll pretend is not there;
1927 for dead cat, the flag will be clear and there'll be
1928 a cat corpse inside the box; either way, inventory
1929 reports the box as containing "1 item" */
1930 cat = SchroedingersBox(box);
1933 Sprintf(buf, "Contents of %s:", the(xname(box)));
1935 Sprintf(buf, "%s
\82Ì
\92\86\90g
\81F", the(xname(box)));
1936 putstr(tmpwin, 0, buf);
1938 putstr(tmpwin, 0, "");
1939 buf[0] = buf[1] = ' '; /* two leading spaces */
1940 if (box->cobj && !cat) {
1941 sortflags = (((flags.sortloot == 'l'
1942 || flags.sortloot == 'f')
1943 ? SORTLOOT_LOOT : 0)
1944 | (flags.sortpack ? SORTLOOT_PACK : 0));
1945 sortedcobj = sortloot(&box->cobj, sortflags, FALSE,
1946 (boolean FDECL((*), (OBJ_P))) 0);
1947 for (srtc = sortedcobj; ((obj = srtc->obj) != 0); ++srtc) {
1949 discover_object(obj->otyp, TRUE, FALSE);
1950 obj->known = obj->bknown = obj->dknown
1952 if (Is_container(obj) || obj->otyp == STATUE)
1953 obj->cknown = obj->lknown = 1;
1955 Strcpy(&buf[2], doname_with_price(obj));
1956 putstr(tmpwin, 0, buf);
1958 unsortloot(&sortedcobj);
1961 Strcpy(&buf[2], "Schroedinger's cat!");
1963 Strcpy(&buf[2], "
\83V
\83\85\83\8c\83f
\83B
\83\93\83K
\81[
\82Ì
\94L
\81I");
1964 putstr(tmpwin, 0, buf);
1968 display_nhwindow(tmpwin, TRUE);
1969 destroy_nhwindow(tmpwin);
1971 container_contents(box->cobj, identified, TRUE,
1973 } else if (reportempty) {
1975 pline("%s is empty.", upstart(thesimpleoname(box)));
1977 pline("%s
\82Í
\8bó
\82Á
\82Û
\82¾
\81D", xname(box));
1978 display_nhwindow(WIN_MESSAGE, FALSE);
1981 if (!all_containers)
1986 /* should be called with either EXIT_SUCCESS or EXIT_FAILURE */
1988 nh_terminate(status)
1991 program_state.in_moveloop = 0; /* won't be returning to normal play */
1993 getreturn("to exit");
1995 /* don't bother to try to release memory if we're in panic mode, to
1996 avoid trouble in case that happens to be due to memory problems */
1997 if (!program_state.panicking) {
2004 * This is liable to draw a warning if compiled with gcc, but it's
2005 * more important to flag panic() -> really_done() -> nh_terminate()
2006 * as __noreturn__ then to avoid the warning.
2008 /* don't call exit() if already executing within an exit handler;
2009 that would cancel any other pending user-mode handlers */
2010 if (program_state.exiting)
2013 program_state.exiting = 1;
2015 jputchar('\0'); /* reset terminal */
2017 nethack_exit(status);
2020 enum vanq_order_modes {
2030 NUM_VANQ_ORDER_MODES
2033 static const char *vanqorders[NUM_VANQ_ORDER_MODES] = {
2034 "traditional: by monster level, by internal monster index",
2035 "by monster toughness, by internal monster index",
2036 "alphabetically, first unique monsters, then others",
2037 "alphabetically, unique monsters and others intermixed",
2038 "by monster class, high to low level within class",
2039 "by monster class, low to high level within class",
2040 "by count, high to low, by internal index within tied count",
2041 "by count, low to high, by internal index within tied count",
2043 static int vanq_sortmode = VANQ_MLVL_MNDX;
2045 STATIC_PTR int CFDECLSPEC
2046 vanqsort_cmp(vptr1, vptr2)
2047 const genericptr vptr1;
2048 const genericptr vptr2;
2050 int indx1 = *(short *) vptr1, indx2 = *(short *) vptr2,
2051 mlev1, mlev2, mstr1, mstr2, uniq1, uniq2, died1, died2, res;
2052 const char *name1, *name2, *punct;
2055 switch (vanq_sortmode) {
2057 case VANQ_MLVL_MNDX:
2058 /* sort by monster level */
2059 mlev1 = mons[indx1].mlevel, mlev2 = mons[indx2].mlevel;
2060 res = mlev2 - mlev1; /* mlevel high to low */
2062 case VANQ_MSTR_MNDX:
2063 /* sort by monster toughness */
2064 mstr1 = mons[indx1].difficulty, mstr2 = mons[indx2].difficulty;
2065 res = mstr2 - mstr1; /* monstr high to low */
2067 case VANQ_ALPHA_SEP:
2068 uniq1 = ((mons[indx1].geno & G_UNIQ) && indx1 != PM_HIGH_PRIEST);
2069 uniq2 = ((mons[indx2].geno & G_UNIQ) && indx2 != PM_HIGH_PRIEST);
2070 if (uniq1 ^ uniq2) { /* one or other uniq, but not both */
2071 res = uniq2 - uniq1;
2073 } /* else both unique or neither unique */
2075 case VANQ_ALPHA_MIX:
2076 name1 = mons[indx1].mname, name2 = mons[indx2].mname;
2077 res = strcmpi(name1, name2); /* caseblind alhpa, low to high */
2079 case VANQ_MCLS_HTOL:
2080 case VANQ_MCLS_LTOH:
2081 /* mons[].mlet is a small integer, 1..N, of type plain char;
2082 if 'char' happens to be unsigned, (mlet1 - mlet2) would yield
2083 an inappropriate result when mlet2 is greater than mlet1,
2084 so force our copies (mcls1, mcls2) to be signed */
2085 mcls1 = (schar) mons[indx1].mlet, mcls2 = (schar) mons[indx2].mlet;
2086 /* S_ANT through S_ZRUTY correspond to lowercase monster classes,
2087 S_ANGEL through S_ZOMBIE correspond to uppercase, and various
2088 punctuation characters are used for classes beyond those */
2089 if (mcls1 > S_ZOMBIE && mcls2 > S_ZOMBIE) {
2090 /* force a specific order to the punctuation classes that's
2091 different from the internal order;
2092 internal order is ok if neither or just one is punctuation
2093 since letters have lower values so come out before punct */
2094 static const char punctclasses[] = {
2095 S_LIZARD, S_EEL, S_GOLEM, S_GHOST, S_DEMON, S_HUMAN, '\0'
2098 if ((punct = index(punctclasses, mcls1)) != 0)
2099 mcls1 = (schar) (S_ZOMBIE + 1 + (int) (punct - punctclasses));
2100 if ((punct = index(punctclasses, mcls2)) != 0)
2101 mcls2 = (schar) (S_ZOMBIE + 1 + (int) (punct - punctclasses));
2103 res = mcls1 - mcls2; /* class */
2105 mlev1 = mons[indx1].mlevel, mlev2 = mons[indx2].mlevel;
2106 res = mlev1 - mlev2; /* mlevel low to high */
2107 if (vanq_sortmode == VANQ_MCLS_HTOL)
2108 res = -res; /* mlevel high to low */
2111 case VANQ_COUNT_H_L:
2112 case VANQ_COUNT_L_H:
2113 died1 = mvitals[indx1].died, died2 = mvitals[indx2].died;
2114 res = died2 - died1; /* dead count high to low */
2115 if (vanq_sortmode == VANQ_COUNT_L_H)
2116 res = -res; /* dead count low to high */
2119 /* tiebreaker: internal mons[] index */
2121 res = indx1 - indx2; /* mndx low to high */
2125 /* returns -1 if cancelled via ESC */
2130 menu_item *selected;
2134 tmpwin = create_nhwindow(NHW_MENU);
2136 any = zeroany; /* zero out all bits */
2137 for (i = 0; i < SIZE(vanqorders); i++) {
2138 if (i == VANQ_ALPHA_MIX || i == VANQ_MCLS_HTOL) /* skip these */
2141 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, vanqorders[i],
2142 (i == vanq_sortmode) ? MENU_SELECTED : MENU_UNSELECTED);
2145 end_menu(tmpwin, "Sort order for vanquished monster counts");
2147 end_menu(tmpwin, "
\93|
\82µ
\82½
\93G
\82Ì
\83\
\81[
\83g
\8f\87");
2149 n = select_menu(tmpwin, PICK_ONE, &selected);
2150 destroy_nhwindow(tmpwin);
2152 choice = selected[0].item.a_int - 1;
2153 /* skip preselected entry if we have more than one item chosen */
2154 if (n > 1 && choice == vanq_sortmode)
2155 choice = selected[1].item.a_int - 1;
2156 free((genericptr_t) selected);
2157 vanq_sortmode = choice;
2159 return (n < 0) ? -1 : vanq_sortmode;
2162 /* #vanquished command */
2166 list_vanquished('a', FALSE);
2170 /* high priests aren't unique but are flagged as such to simplify something */
2171 #define UniqCritterIndx(mndx) ((mons[mndx].geno & G_UNIQ) \
2172 && mndx != PM_HIGH_PRIEST)
2175 list_vanquished(defquery, ask)
2181 unsigned ntypes, ni;
2182 long total_killed = 0L;
2184 short mindx[NUMMONS];
2185 char c, buf[BUFSZ], buftoo[BUFSZ];
2186 boolean dumping; /* for DUMPLOG; doesn't need to be conditional */
2188 dumping = (defquery == 'd');
2192 /* get totals first */
2194 for (i = LOW_PM; i < NUMMONS; i++) {
2195 if ((nkilled = (int) mvitals[i].died) == 0)
2197 mindx[ntypes++] = i;
2198 total_killed += (long) nkilled;
2201 /* vanquished creatures list;
2202 * includes all dead monsters, not just those killed by the player
2205 char mlet, prev_mlet = 0; /* used as small integer, not character */
2206 boolean class_header, uniq_header, was_uniq = FALSE;
2209 c = ask ? yn_function(
2210 "Do you want an account of creatures vanquished?",
2211 ynaqchars, defquery)
2214 c = ask ? yn_function(
2215 "
\93|
\82µ
\82½
\93G
\82Ì
\88ê
\97\97\82ð
\8c©
\82Ü
\82·
\82©
\81H",
2221 if (c == 'y' || c == 'a') {
2222 if (c == 'a') { /* ask player to choose sort order */
2223 /* choose value for vanq_sortmode via menu; ESC cancels list
2224 of vanquished monsters but does not set 'done_stopprint' */
2225 if (set_vanq_order() < 0)
2228 uniq_header = (vanq_sortmode == VANQ_ALPHA_SEP);
2229 class_header = (vanq_sortmode == VANQ_MCLS_LTOH
2230 || vanq_sortmode == VANQ_MCLS_HTOL);
2232 klwin = create_nhwindow(NHW_MENU);
2234 putstr(klwin, 0, "Vanquished creatures:");
2236 putstr(klwin, 0, "
\93|
\82µ
\82½
\93G
\81F");
2238 putstr(klwin, 0, "");
2240 qsort((genericptr_t) mindx, ntypes, sizeof *mindx, vanqsort_cmp);
2241 for (ni = 0; ni < ntypes; ni++) {
2243 nkilled = mvitals[i].died;
2244 mlet = mons[i].mlet;
2245 if (class_header && mlet != prev_mlet) {
2246 Strcpy(buf, def_monsyms[(int) mlet].explain);
2247 putstr(klwin, ask ? 0 : iflags.menu_headings,
2251 if (UniqCritterIndx(i)) {
2253 Sprintf(buf, "%s%s",
2254 !type_is_pname(&mons[i]) ? "the " : "",
2257 Sprintf(buf, "%s", mons[i].mname);
2263 Sprintf(eos(buf), " (twice)");
2266 Sprintf(eos(buf), " (thrice)");
2269 Sprintf(eos(buf), " (%d times)", nkilled);
2273 Sprintf(eos(buf)," (%d
\89ñ)", nkilled);
2278 if (uniq_header && was_uniq) {
2279 putstr(klwin, 0, "");
2282 /* trolls or undead might have come back,
2283 but we don't keep track of that */
2285 Strcpy(buf, an(mons[i].mname));
2288 Sprintf(buf, "%3d %s", nkilled,
2289 makeplural(mons[i].mname));
2291 Sprintf(buf, "%d
\91Ì
\82Ì%s", nkilled,
2295 /* number of leading spaces to match 3 digit prefix */
2297 pfx = !strncmpi(buf, "the ", 3) ? 0
2298 : !strncmpi(buf, "an ", 3) ? 1
2299 : !strncmpi(buf, "a ", 2) ? 2
2300 : !digit(buf[2]) ? 4 : 0;
2302 pfx = !digit(buf[2]) ? 4 : 0;
2306 Sprintf(buftoo, "%*s%s", pfx, "", buf);
2307 putstr(klwin, 0, buftoo);
2310 * if (Hallucination)
2311 * putstr(klwin, 0, "and a partridge in a pear tree");
2315 putstr(klwin, 0, "");
2317 Sprintf(buf, "%ld creatures vanquished.", total_killed);
2319 Sprintf(buf, "%ld
\95C
\82Ì
\93G
\82ð
\93|
\82µ
\82½
\81D", total_killed);
2320 putstr(klwin, 0, buf);
2322 display_nhwindow(klwin, TRUE);
2323 destroy_nhwindow(klwin);
2325 } else if (defquery == 'a') {
2326 /* #dovanquished rather than final disclosure, so pline() is ok */
2328 pline("No creatures have been vanquished.");
2330 pline("
\93|
\82µ
\82½
\93G
\82Í
\82¢
\82È
\82©
\82Á
\82½
\81D");
2332 } else if (dumping) {
2333 putstr(0, 0, "No creatures were vanquished."); /* not pline() */
2338 /* number of monster species which have been genocided */
2344 for (i = LOW_PM; i < NUMMONS; ++i) {
2345 if (mvitals[i].mvflags & G_GENOD) {
2347 if (UniqCritterIndx(i))
2348 impossible("unique creature '%d: %s' genocided?",
2360 for (i = LOW_PM; i < NUMMONS; ++i) {
2361 if (UniqCritterIndx(i))
2363 if ((mvitals[i].mvflags & G_GONE) == G_EXTINCT)
2370 list_genocided(defquery, ask)
2375 int ngenocided, nextinct;
2379 boolean dumping; /* for DUMPLOG; doesn't need to be conditional */
2381 dumping = (defquery == 'd');
2385 ngenocided = num_genocides();
2386 nextinct = num_extinct();
2388 /* genocided or extinct species list */
2389 if (ngenocided != 0 || nextinct != 0) {
2391 Sprintf(buf, "Do you want a list of %sspecies%s%s?",
2392 (nextinct && !ngenocided) ? "extinct " : "",
2393 (ngenocided) ? " genocided" : "",
2394 (nextinct && ngenocided) ? " and extinct" : "");
2396 Sprintf(buf, "%s%s%s
\82µ
\82½
\8eí
\82Ì
\88ê
\97\97\82ð
\8c©
\82Ü
\82·
\82©
\81H",
2397 (nextinct && !ngenocided) ? "
\90â
\96Å" : "",
2398 (ngenocided) ? "
\8bs
\8eE" : "",
2399 (nextinct && ngenocided) ? "
\82¨
\82æ
\82Ñ
\90â
\96Å" : "");
2401 c = ask ? yn_function(buf, ynqchars, defquery) : defquery;
2405 klwin = create_nhwindow(NHW_MENU);
2407 Sprintf(buf, "%s%s species:",
2408 (ngenocided) ? "Genocided" : "Extinct",
2409 (nextinct && ngenocided) ? " or extinct" : "");
2411 Sprintf(buf, "%s%s
\82µ
\82½
\8eí:",
2412 (ngenocided) ? "
\8bs
\8eE" : "
\90â
\96Å",
2413 (nextinct && ngenocided) ? "
\82Ü
\82½
\82Í
\90â
\96Å" : "");
2415 putstr(klwin, 0, buf);
2417 putstr(klwin, 0, "");
2419 for (i = LOW_PM; i < NUMMONS; i++) {
2420 /* uniques can't be genocided but can become extinct;
2421 however, they're never reported as extinct, so skip them */
2422 if (UniqCritterIndx(i))
2424 if (mvitals[i].mvflags & G_GONE) {
2425 Sprintf(buf, " %s", makeplural(mons[i].mname));
2427 * "Extinct" is unfortunate terminology. A species
2428 * is marked extinct when its birth limit is reached,
2429 * but there might be members of the species still
2430 * alive, contradicting the meaning of the word.
2432 if ((mvitals[i].mvflags & G_GONE) == G_EXTINCT)
2434 Strcat(buf, " (extinct)");
2436 Strcat(buf, "(
\90â
\96Å)");
2437 putstr(klwin, 0, buf);
2441 putstr(klwin, 0, "");
2442 if (ngenocided > 0) {
2444 Sprintf(buf, "%d species genocided.", ngenocided);
2446 Sprintf(buf, "%d
\8eí
\97Þ
\82Ì
\8eí
\82ð
\8bs
\8eE
\82µ
\82½
\81D", ngenocided);
2447 putstr(klwin, 0, buf);
2451 Sprintf(buf, "%d species extinct.", nextinct);
2453 Sprintf(buf, "%d
\8eí
\97Þ
\82Ì
\8eí
\82ð
\90â
\96Å
\82³
\82¹
\82½
\81D", nextinct);
2454 putstr(klwin, 0, buf);
2457 display_nhwindow(klwin, TRUE);
2458 destroy_nhwindow(klwin);
2461 } else if (dumping) {
2462 putstr(0, 0, "No species were genocided or became extinct.");
2467 /* set a delayed killer, ensure non-delayed killer is cleared out */
2469 delayed_killer(id, format, killername)
2472 const char *killername;
2474 struct kinfo *k = find_delayed_killer(id);
2477 /* no match, add a new delayed killer to the list */
2478 k = (struct kinfo *) alloc(sizeof (struct kinfo));
2479 (void) memset((genericptr_t) k, 0, sizeof (struct kinfo));
2481 k->next = killer.next;
2486 Strcpy(k->name, killername ? killername : "");
2491 find_delayed_killer(id)
2496 for (k = killer.next; k != (struct kinfo *) 0; k = k->next) {
2504 dealloc_killer(kptr)
2507 struct kinfo *prev = &killer, *k;
2509 if (kptr == (struct kinfo *) 0)
2511 for (k = killer.next; k != (struct kinfo *) 0; k = k->next) {
2517 if (k == (struct kinfo *) 0) {
2518 impossible("dealloc_killer (#%d) not on list", kptr->id);
2520 prev->next = k->next;
2521 free((genericptr_t) k);
2522 debugpline1("freed delayed killer #%d", kptr->id);
2527 save_killers(fd, mode)
2533 if (perform_bwrite(mode)) {
2534 for (kptr = &killer; kptr != (struct kinfo *) 0; kptr = kptr->next) {
2535 bwrite(fd, (genericptr_t) kptr, sizeof (struct kinfo));
2538 if (release_data(mode)) {
2539 while (killer.next) {
2540 kptr = killer.next->next;
2541 free((genericptr_t) killer.next);
2553 for (kptr = &killer; kptr != (struct kinfo *) 0; kptr = kptr->next) {
2554 mread(fd, (genericptr_t) kptr, sizeof (struct kinfo));
2556 kptr->next = (struct kinfo *) alloc(sizeof (struct kinfo));
2568 while (*p && isspace((uchar) *p))
2572 while (*p && !isspace((uchar) *p))
2584 out += strlen(out); /* eos() */
2585 while (*in && isspace((uchar) *in))
2587 while (*in && !isspace((uchar) *in))
2593 /*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*/
2595 build_english_list(in)
2599 int len = (int) strlen(p), words = wordcount(p);
2601 /* +3: " or " - " "; +(words - 1): (N-1)*(", " - " ") */
2603 len += 3 + (words - 1);
2604 out = (char *) alloc(len + 1);
2605 *out = '\0'; /* bel_copy1() appends */
2609 impossible("no words in list");
2617 /* "first or second" */
2621 /* "first, second, or third */
2625 } while (--words > 1);