1 /* NetHack 3.6 end.c $NHDT-Date: 1512803167 2017/12/09 07:06:07 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.137 $ */
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 */
17 /* add b to long a, convert wraparound to max value */
18 #define nowrap_add(a, b) (a = ((a + b) < 0 ? LONG_MAX : (a + b)))
20 /* these probably ought to be generated by makedefs, like LAST_GEM */
21 #define FIRST_GEM DILITHIUM_CRYSTAL
22 #define FIRST_AMULET AMULET_OF_ESP
23 #define LAST_AMULET AMULET_OF_YENDOR
25 struct valuable_data {
30 static struct valuable_data
31 gems[LAST_GEM + 1 - FIRST_GEM + 1], /* 1 extra for glass */
32 amulets[LAST_AMULET + 1 - FIRST_AMULET];
34 static struct val_list {
35 struct valuable_data *list;
37 } valuables[] = { { gems, sizeof gems / sizeof *gems },
38 { amulets, sizeof amulets / sizeof *amulets },
42 STATIC_PTR void FDECL(done_intr, (int));
43 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
44 static void FDECL(done_hangup, (int));
47 STATIC_DCL void FDECL(disclose, (int, BOOLEAN_P));
48 STATIC_DCL void FDECL(get_valuables, (struct obj *));
49 STATIC_DCL void FDECL(sort_valuables, (struct valuable_data *, int));
50 STATIC_DCL void FDECL(artifact_score, (struct obj *, BOOLEAN_P, winid));
51 STATIC_DCL void FDECL(really_done, (int)) NORETURN;
52 STATIC_DCL boolean FDECL(odds_and_ends, (struct obj *, int));
53 STATIC_DCL void FDECL(savelife, (int));
54 STATIC_PTR int FDECL(CFDECLSPEC vanqsort_cmp, (const genericptr,
56 STATIC_DCL int NDECL(set_vanq_order);
57 STATIC_DCL void FDECL(list_vanquished, (CHAR_P, BOOLEAN_P));
58 STATIC_DCL void FDECL(list_genocided, (CHAR_P, BOOLEAN_P));
59 STATIC_DCL boolean FDECL(should_query_disclose_option, (int, char *));
61 STATIC_DCL void NDECL(dump_plines);
63 STATIC_DCL void FDECL(dump_everything, (int, time_t));
64 STATIC_DCL int NDECL(num_extinct);
66 #if defined(__BEOS__) || defined(MICRO) || defined(WIN32) || defined(OS2)
67 extern void FDECL(nethack_exit, (int));
69 #define nethack_exit exit
72 #define done_stopprint program_state.stopprint
75 #define NH_abort NH_abort_
79 #define NH_abort_() Abort(0)
82 #define NH_abort_() (void) abort()
85 #define NH_abort_() win32_abort()
87 #define NH_abort_() abort()
94 #ifdef PANICTRACE_LIBC
98 /* What do we try and in what order? Tradeoffs:
99 * libc: +no external programs required
100 * -requires newish libc/glibc
101 * -requires -rdynamic
102 * gdb: +gives more detailed information
103 * +works on more OS versions
104 * -requires -g, which may preclude -O on some compilers
107 #define SYSOPT_PANICTRACE_GDB sysopt.panictrace_gdb
108 #ifdef PANICTRACE_LIBC
109 #define SYSOPT_PANICTRACE_LIBC sysopt.panictrace_libc
111 #define SYSOPT_PANICTRACE_LIBC 0
114 #define SYSOPT_PANICTRACE_GDB (nh_getenv("NETHACK_USE_GDB") == 0 ? 0 : 2)
115 #ifdef PANICTRACE_LIBC
116 #define SYSOPT_PANICTRACE_LIBC 1
118 #define SYSOPT_PANICTRACE_LIBC 0
122 static void NDECL(NH_abort);
124 static void FDECL(panictrace_handler, (int));
126 static boolean NDECL(NH_panictrace_libc);
127 static boolean NDECL(NH_panictrace_gdb);
131 void panictrace_handler(
132 sig_unused) /* called as signal() handler, so sent at least one arg */
133 int sig_unused UNUSED;
135 #define SIG_MSG "\nSignal received.\n"
136 (void) write(2, SIG_MSG, sizeof(SIG_MSG) - 1);
141 panictrace_setsignals(set)
144 #define SETSIGNAL(sig) \
145 (void) signal(sig, set ? (SIG_RET_TYPE) panictrace_handler : SIG_DFL);
165 SETSIGNAL(SIGSTKFLT);
175 #endif /* NO_SIGNAL */
180 int gdb_prio = SYSOPT_PANICTRACE_GDB;
181 int libc_prio = SYSOPT_PANICTRACE_LIBC;
182 static boolean aborting = FALSE;
189 if (gdb_prio == libc_prio && gdb_prio > 0)
192 if (gdb_prio > libc_prio) {
193 (void) (NH_panictrace_gdb() || (libc_prio && NH_panictrace_libc()));
195 (void) (NH_panictrace_libc() || (gdb_prio && NH_panictrace_gdb()));
199 /* overload otherwise unused priority for debug mode: 1 = show
200 traceback and exit; 2 = show traceback and stay in debugger */
201 /* if (wizard && gdb_prio == 1) gdb_prio = 2; */
202 vms_traceback(gdb_prio);
203 (void) libc_prio; /* half-hearted attempt at lint suppression */
208 panictrace_setsignals(FALSE);
216 #ifdef PANICTRACE_LIBC
221 raw_print("Generating more information you may report:\n");
222 count = backtrace(bt, SIZE(bt));
223 info = backtrace_symbols(bt, count);
224 for (x = 0; x < count; x++) {
225 raw_printf("[%lu] %s", (unsigned long) x, info[x]);
227 /* free(info); -- Don't risk it. */
231 #endif /* !PANICTRACE_LIBC */
235 * fooPATH file system path for foo
236 * fooVAR (possibly const) variable containing fooPATH
238 #ifdef PANICTRACE_GDB
240 #define GDBVAR sysopt.gdbpath
241 #define GREPVAR sysopt.greppath
243 #define GDBVAR GDBPATH
244 #define GREPVAR GREPPATH
246 #endif /* PANICTRACE_GDB */
251 #ifdef PANICTRACE_GDB
252 /* A (more) generic method to get a stack trace - invoke
254 char *gdbpath = GDBVAR;
255 char *greppath = GREPVAR;
259 if (gdbpath == NULL || gdbpath[0] == 0)
261 if (greppath == NULL || greppath[0] == 0)
264 sprintf(buf, "%s -n -q %s %d 2>&1 | %s '^#'", gdbpath, ARGV0, getpid(),
266 gdb = popen(buf, "w");
268 raw_print("Generating more information you may report:\n");
269 fprintf(gdb, "bt\nquit\ny");
279 #endif /* !PANICTRACE_GDB */
281 #endif /* PANICTRACE */
283 #if 0 /*JP*//*
\93ú
\96{
\8cê
\82Å
\82Í
\8eg
\82í
\82È
\82¢*/
285 * The order of these needs to match the macros in hack.h.
287 static NEARDATA const char *deaths[] = {
288 /* the array of death */
289 "died", "choked", "poisoned", "starvation", "drowning", "burning",
290 "dissolving under the heat and pressure", "crushed", "turned to stone",
291 "turned into slime", "genocided", "panic", "trickery", "quit",
292 "escaped", "ascended"
296 static NEARDATA const char *ends[] = {
299 "died", "choked", "were poisoned",
300 "starved", "drowned", "burned",
301 "dissolved in the lava",
302 "were crushed", "turned to stone",
303 "turned into slime", "were genocided",
304 "panicked", "were tricked", "quit",
305 "escaped", "ascended"
306 #else /*JP:
\8dÅ
\8cã
\82É
\81u
\8eE
\82³
\82ê
\82½
\81v
\92Ç
\89Á */
307 "
\8e\80\82ñ
\82¾", "
\92\82\91§
\82µ
\82½", "
\93Å
\82É
\82¨
\82©
\82³
\82ê
\82½",
308 "
\89ì
\8e\80\82µ
\82½", "
\93M
\8e\80\82µ
\82½", "
\8fÄ
\8e\80\82µ
\82½",
309 "
\97n
\8aâ
\82É
\97n
\82¯
\82½",
310 "
\89\9f\82µ
\92×
\82³
\82ê
\82½", "
\90Î
\82É
\82È
\82Á
\82½",
311 "
\82Ç
\82ë
\82Ç
\82ë
\82É
\97n
\82¯
\82½", "
\8bs
\8eE
\82³
\82ê
\82½",
312 "
\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½",
313 "
\92E
\8fo
\82µ
\82½", "
\8f¸
\93V
\82µ
\82½", "
\8eE
\82³
\82ê
\82½"
317 static boolean Schroedingers_cat = FALSE;
321 done1(sig_unused) /* called as signal() handler, so sent at least one arg */
322 int sig_unused UNUSED;
325 (void) signal(SIGINT, SIG_IGN);
329 (void) signal(SIGINT, (SIG_RET_TYPE) done1);
331 clear_nhwindow(WIN_MESSAGE);
341 /* "#quit" command or keyboard interrupt */
346 if (!paranoid_query(ParanoidQuit, "Really quit?")) {
348 if (!paranoid_query(ParanoidQuit, "
\96{
\93\96\82É
\82â
\82ß
\82é
\81H")) {
350 (void) signal(SIGINT, (SIG_RET_TYPE) done1);
352 clear_nhwindow(WIN_MESSAGE);
358 u.uinvulnerable = FALSE; /* avoid ctrl-C bug -dlc */
363 #if (defined(UNIX) || defined(VMS) || defined(LATTICE))
367 extern int debuggable; /* sys/vms/vmsmisc.c, vmsunix.c */
369 c = !debuggable ? 'n' : ynq("Enter debugger?");
372 c = ynq("Create SnapShot?");
374 c = ynq("Dump core?");
379 (void) signal(SIGINT, (SIG_RET_TYPE) done1);
381 exit_nhwindows((char *) 0);
396 done_intr(sig_unused) /* called as signal() handler, so sent at least 1 arg */
397 int sig_unused UNUSED;
400 (void) signal(SIGINT, SIG_IGN);
401 #if defined(UNIX) || defined(VMS)
402 (void) signal(SIGQUIT, SIG_IGN);
407 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
408 /* signal() handler */
413 program_state.done_hup++;
414 sethanguphandler((void FDECL((*), (int) )) SIG_IGN);
419 #endif /* NO_SIGNAL */
422 done_in_by(mtmp, how)
427 struct permonst *mptr = mtmp->data,
428 *champtr = ((mtmp->cham >= LOW_PM)
431 boolean distorted = (boolean) (Hallucination && canspotmon(mtmp)),
432 mimicker = (mtmp->m_ap_type == M_AP_MONSTER),
433 imitator = (mptr != champtr || mimicker);
436 You((how == STONING) ? "turn to stone..." : "die...");
438 You((how == STONING) ? "
\90Î
\82É
\82È
\82Á
\82½
\81D
\81D
\81D" : "
\8e\80\82É
\82Ü
\82µ
\82½
\81D
\81D
\81D");
439 mark_synch(); /* flush buffered screen output */
441 killer.format = KILLED_BY_AN;
442 #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 */
443 /* "killed by the high priest of Crom" is okay,
444 "killed by the high priest" alone isn't */
445 if ((mptr->geno & G_UNIQ) != 0 && !(imitator && !mimicker)
446 && !(mptr == &mons[PM_HIGH_PRIEST] && !mtmp->ispriest)) {
447 if (!type_is_pname(mptr))
449 killer.format = KILLED_BY;
451 /* _the_ <invisible> <distorted> ghost of Dudley */
452 if (mptr == &mons[PM_GHOST] && has_mname(mtmp)) {
454 killer.format = KILLED_BY;
459 Strcat(buf, "invisible ");
461 Strcat(buf, "
\93§
\96¾
\82È");
464 Strcat(buf, "hallucinogen-distorted ");
466 Strcat(buf, "
\8c¶
\8ao
\82Å
\98c
\82ñ
\82¾");
470 const char *realnm = champtr->mname, *fakenm = mptr->mname;
471 boolean alt = is_vampshifter(mtmp);
474 /* realnm is already correct because champtr==mptr;
475 set up fake mptr for type_is_pname/the_unique_pm */
476 mptr = &mons[mtmp->mappearance];
477 fakenm = mptr->mname;
479 } else if (alt && strstri(realnm, "vampire")
480 && !strcmp(fakenm, "vampire bat")) {
481 /* special case: use "vampire in bat form" in preference
482 to redundant looking "vampire in vampire bat form" */
485 } else if (alt && strstri(realnm, "
\8bz
\8c\8c\8bS")
486 && !strcmp(fakenm, "
\8bz
\8c\8c\82±
\82¤
\82à
\82è")) {
487 /*
\81u
\8bz
\8c\8c\82±
\82¤
\82à
\82è
\82Ì
\8ep
\82Ì
\8bz
\8c\8c\8bS
\81v
\82Í
\8fç
\92·
\82È
\82Ì
\82Å
488 \81u
\82±
\82¤
\82à
\82è
\82Ì
\8ep
\82Ì
\8bz
\8c\8c\8bS
\81v
\82Ì
\8c`
\82É
\82·
\82é */
489 fakenm = "
\82±
\82¤
\82à
\82è";
493 /* for the alternate format, always suppress any article;
494 pname and the_unique should also have s_suffix() applied,
495 but vampires don't take on any shapes which warrant that */
496 if (alt || type_is_pname(mptr)) /* no article */
497 Strcpy(shape, fakenm);
498 else if (the_unique_pm(mptr)) /* "the"; don't use the() here */
499 Sprintf(shape, "the %s", fakenm);
501 Strcpy(shape, an(fakenm));
502 #else /*JP:
\93ú
\96{
\8cê
\82Å
\82Í
\83V
\83\93\83v
\83\8b*/
503 Strcpy(shape, fakenm);
505 /* omit "called" to avoid excessive verbosity */
508 alt ? "%s in %s form"
509 : mimicker ? "%s disguised as %s"
514 alt ? "%s
\82Ì
\8ep
\82Ì%s"
515 : mimicker ? "%s
\82Ì
\82Ó
\82è
\82ð
\82µ
\82Ä
\82¢
\82é%s"
516 : "%s
\82Ì
\82Ü
\82Ë
\82ð
\82µ
\82Ä
\82¢
\82é%s",
519 mptr = mtmp->data; /* reset for mimicker case */
520 } else if (mptr == &mons[PM_GHOST]) {
522 Strcat(buf, "ghost");
524 Sprintf(eos(buf), " of %s", MNAME(mtmp));
527 Sprintf(eos(buf), "%s
\82Ì
\97H
\97ì", MNAME(mtmp));
529 Strcat(buf, "
\97H
\97ì");
531 } else if (mtmp->isshk) {
533 const char *shknm = shkname(mtmp),
534 *honorific = shkname_is_pname(mtmp) ? ""
535 : mtmp->female ? "Ms. " : "Mr. ";
537 Sprintf(eos(buf), "%s%s, the shopkeeper", honorific, shknm);
539 Sprintf(eos(buf), "%s
\82Æ
\82¢
\82¤
\96¼
\82Ì
\93X
\8eå", shkname(mtmp));
541 killer.format = KILLED_BY;
542 } else if (mtmp->ispriest || mtmp->isminion) {
543 /* m_monnam() suppresses "the" prefix plus "invisible", and
544 it overrides the effect of Hallucination on priestname() */
545 Strcat(buf, m_monnam(mtmp));
548 Strcat(buf, mptr->mname);
550 Sprintf(eos(buf), " called %s", MNAME(mtmp));
552 Strcat(buf, mptr->mname);
556 Strcpy(killer.name, buf);
557 if (mptr->mlet == S_WRAITH)
558 u.ugrave_arise = PM_WRAITH;
559 else if (mptr->mlet == S_MUMMY && urace.mummynum != NON_PM)
560 u.ugrave_arise = urace.mummynum;
561 else if (mptr->mlet == S_VAMPIRE && Race_if(PM_HUMAN))
562 u.ugrave_arise = PM_VAMPIRE;
563 else if (mptr == &mons[PM_GHOUL])
564 u.ugrave_arise = PM_GHOUL;
565 /* this could happen if a high-end vampire kills the hero
566 when ordinary vampires are genocided; ditto for wraiths */
567 if (u.ugrave_arise >= LOW_PM
568 && (mvitals[u.ugrave_arise].mvflags & G_GENOD))
569 u.ugrave_arise = NON_PM;
574 topten.c
\82Ì killed_by_prefix
\82ð
\8eQ
\8fÆ
\82Ì
\82±
\82Æ
\81B
575 STONING
\82Ì
\8fê
\8d\87\82Í "
\90Î
\89»
\82µ
\82½"
\82ª
\95â
\82í
\82ê
\82é
\81B
577 Strcat(buf, "
\82Ì
\8dU
\8c\82\82Å");
581 DIED
\82Ì
\8fê
\8d\87\82Í
\92Ê
\8fí "
\8e\80\82ñ
\82¾"
\82ª
\95â
\82í
\82ê
\82é
\82ª
\81A
582 \89ö
\95¨
\82É
\82æ
\82é
\8fê
\8d\87\82Í "
\82É
\8eE
\82³
\82ê
\82½"
\82ð
\95â
\82¤
\81B
584 killer.format = KILLED_SUFFIX;
592 /* some special cases for overriding while-helpless reason */
593 static const struct {
595 const char *exclude, *include;
597 /* "petrified by <foo>, while getting stoned" -- "while getting stoned"
598 prevented any last-second recovery, but it was not the cause of
599 "petrified by <foo>" */
600 { STONING, 1, "getting stoned", (char *) 0 },
601 /* "died of starvation, while fainted from lack of food" is accurate
602 but sounds a fairly silly (and doesn't actually appear unless you
603 splice together death and while-helpless from xlogfile) */
604 { STARVING, 0, "fainted from lack of food", "fainted" },
607 /* clear away while-helpless when the cause of death caused that
608 helplessness (ie, "petrified by <foo> while getting stoned") */
616 for (i = 0; i < SIZE(death_fixups); ++i)
617 if (death_fixups[i].why == how
618 && !strcmp(death_fixups[i].exclude, multi_reason)) {
619 if (death_fixups[i].include) /* substitute alternate reason */
620 multi_reason = death_fixups[i].include;
621 else /* remove the helplessness reason */
622 multi_reason = (char *) 0;
623 if (death_fixups[i].unmulti) /* possibly hide helplessness */
630 #if defined(WIN32) && !defined(SYSCF)
631 #define NOTIFY_NETHACK_BUGS
636 VA_DECL(const char *, str)
639 VA_INIT(str, char *);
641 if (program_state.panicking++)
642 NH_abort(); /* avoid loops - this should never happen*/
644 if (iflags.window_inited) {
645 raw_print("\r\nOops...");
646 wait_synch(); /* make sure all pending output gets flushed */
647 exit_nhwindows((char *) 0);
648 iflags.window_inited = 0; /* they're gone; force raw_print()ing */
651 raw_print(program_state.gameover
653 ? "Postgame wrapup disrupted."
655 ? "
\83Q
\81[
\83\80\8fI
\97¹
\8e\9e\82Ì
\8f\88\97\9d\82ª
\95ö
\89ó
\82µ
\82½
\81D"
656 : !program_state.something_worth_saving
658 ? "Program initialization has failed."
660 ? "
\83v
\83\8d\83O
\83\89\83\80\82Ì
\8f\89\8aú
\89»
\82É
\8e¸
\94s
\82µ
\82½
\81D"
662 : "Suddenly, the dungeon collapses.");
664 : "
\93Ë
\91R
\96À
\8b{
\82ª
\95ö
\82ê
\82½
\81D");
666 #if defined(NOTIFY_NETHACK_BUGS)
668 raw_printf("Report the following error to \"%s\" or at \"%s\".",
669 DEVTEAM_EMAIL, DEVTEAM_URL);
670 else if (program_state.something_worth_saving)
671 raw_print("\nError save file being written.\n");
675 const char *maybe_rebuild = !program_state.something_worth_saving
677 : "\nand it may be possible to rebuild.";
679 const char *maybe_rebuild = !program_state.something_worth_saving
681 : "\n
\95\9c\8b\8c\82Å
\82«
\82é
\89Â
\94\
\90«
\82ª
\82 \82è
\82Ü
\82·
\81D";
685 raw_printf("To report this error, %s%s", sysopt.support,
687 else if (sysopt.fmtd_wizard_list) /* formatted SYSCF WIZARDS */
688 raw_printf("To report this error, contact %s%s",
689 sysopt.fmtd_wizard_list, maybe_rebuild);
692 raw_printf("Report error to \"%s\"%s", WIZARD_NAME,
695 raw_printf("\"%s\"
\82É
\83G
\83\89\81[
\82ð
\95ñ
\8d\90\82µ
\82Ä
\82
\82¾
\82³
\82¢
\81D%s", WIZARD_NAME,
700 /* XXX can we move this above the prints? Then we'd be able to
701 * suppress "it may be possible to rebuild" based on dosave0()
702 * or say it's NOT possible to rebuild. */
703 if (program_state.something_worth_saving) {
704 set_error_savefile();
706 /* os/win port specific recover instructions */
708 raw_printf("%s", sysopt.recover);
715 Vsprintf(buf, str, VA_ARGS);
717 paniclog("panic", buf);
720 interject(INTERJECT_PANIC);
722 #if defined(UNIX) || defined(VMS) || defined(LATTICE) || defined(WIN32)
724 NH_abort(); /* generate core dump */
727 really_done(PANICKED);
731 should_query_disclose_option(category, defquery)
739 if ((dop = index(disclosure_options, category)) != 0) {
740 idx = (int) (dop - disclosure_options);
741 if (idx < 0 || idx >= NUM_DISCLOSURE_OPTIONS) {
743 "should_query_disclose_option: bad disclosure index %d %c",
745 *defquery = DISCLOSE_PROMPT_DEFAULT_YES;
748 disclose = flags.end_disclose[idx];
749 if (disclose == DISCLOSE_YES_WITHOUT_PROMPT) {
752 } else if (disclose == DISCLOSE_SPECIAL_WITHOUT_PROMPT) {
755 } else if (disclose == DISCLOSE_NO_WITHOUT_PROMPT) {
758 } else if (disclose == DISCLOSE_PROMPT_DEFAULT_YES) {
761 } else if (disclose == DISCLOSE_PROMPT_DEFAULT_SPECIAL) {
769 impossible("should_query_disclose_option: bad category %c", category);
778 char buf[BUFSZ], **strp;
779 extern char *saved_plines[];
780 extern unsigned saved_pline_index;
782 Strcpy(buf, " "); /* one space for indentation */
783 putstr(0, 0, "Latest messages:");
784 for (i = 0, j = (int) saved_pline_index; i < DUMPLOG_MSG_COUNT;
785 ++i, j = (j + 1) % DUMPLOG_MSG_COUNT) {
786 strp = &saved_plines[j];
788 copynchars(&buf[1], *strp, BUFSZ - 1 - 1);
790 #ifdef FREE_ALL_MEMORY
791 free(*strp), *strp = 0;
800 dump_everything(how, when)
802 time_t when; /* date+time at end of game */
805 char pbuf[BUFSZ], datetimebuf[24]; /* [24]: room for 64-bit bogus value */
808 if (!iflags.in_dumplog)
811 init_symbols(); /* revert to default symbol set */
813 /* one line version ID, which includes build date+time;
814 it's conceivable that the game started with a different
815 build date+time or even with an older nethack version,
816 but we only have access to the one it finished under */
817 putstr(0, 0, getversionstring(pbuf));
820 /* game start and end date+time to disambiguate version date+time */
821 Strcpy(datetimebuf, yyyymmddhhmmss(ubirthday));
822 Sprintf(pbuf, "Game began %4.4s-%2.2s-%2.2s %2.2s:%2.2s:%2.2s",
823 &datetimebuf[0], &datetimebuf[4], &datetimebuf[6],
824 &datetimebuf[8], &datetimebuf[10], &datetimebuf[12]);
825 Strcpy(datetimebuf, yyyymmddhhmmss(when));
826 Sprintf(eos(pbuf), ", ended %4.4s-%2.2s-%2.2s %2.2s:%2.2s:%2.2s.",
827 &datetimebuf[0], &datetimebuf[4], &datetimebuf[6],
828 &datetimebuf[8], &datetimebuf[10], &datetimebuf[12]);
832 /* character name and basic role info */
833 Sprintf(pbuf, "%s, %s %s %s %s", plname,
834 aligns[1 - u.ualign.type].adj,
835 genders[flags.female].adj,
837 (flags.female && urole.name.f) ? urole.name.f : urole.name.m);
842 putstr(0, 0, do_statusline1());
843 putstr(0, 0, do_statusline2());
848 putstr(0, 0, "Inventory:");
849 display_inventory((char *) 0, TRUE);
850 container_contents(invent, TRUE, TRUE, FALSE);
851 enlightenment((BASICENLIGHTENMENT | MAGICENLIGHTENMENT),
852 (how >= PANICKED) ? ENL_GAMEOVERALIVE : ENL_GAMEOVERDEAD);
854 list_vanquished('d', FALSE); /* 'd' => 'y' */
856 list_genocided('d', FALSE); /* 'd' => 'y' */
858 show_conduct((how >= PANICKED) ? 1 : 2);
860 show_overview((how >= PANICKED) ? 1 : 2, how);
862 dump_redirect(FALSE);
874 char c = '\0', defquery;
878 if (invent && !done_stopprint) {
881 Sprintf(qbuf, "Do you want to see what you had when you %s?",
882 (how == QUIT) ? "quit" : "died");
884 Sprintf(qbuf,"%s
\82Æ
\82«
\89½
\82ð
\8e\9d\82Á
\82Ä
\82¢
\82½
\82©
\8c©
\82Ü
\82·
\82©
\81H",
885 (how == QUIT) ? "
\82â
\82ß
\82½" : "
\8e\80\82ñ
\82¾");
889 Strcpy(qbuf, "Do you want your possessions identified?");
891 Strcpy(qbuf,"
\8e\9d\82¿
\95¨
\82ð
\8e¯
\95Ê
\82µ
\82Ü
\82·
\82©
\81H");
893 ask = should_query_disclose_option('i', &defquery);
894 c = ask ? yn_function(qbuf, ynqchars, defquery) : defquery;
896 /* caller has already ID'd everything */
897 (void) display_inventory((char *) 0, TRUE);
898 container_contents(invent, TRUE, TRUE, FALSE);
904 if (!done_stopprint) {
905 ask = should_query_disclose_option('a', &defquery);
907 c = ask ? yn_function("Do you want to see your attributes?", ynqchars,
911 c = ask ? yn_function("
\91®
\90«
\82ð
\8c©
\82Ü
\82·
\82©
\81H", ynqchars,
916 enlightenment((BASICENLIGHTENMENT | MAGICENLIGHTENMENT),
917 (how >= PANICKED) ? ENL_GAMEOVERALIVE
923 if (!done_stopprint) {
924 ask = should_query_disclose_option('v', &defquery);
925 list_vanquished(defquery, ask);
928 if (!done_stopprint) {
929 ask = should_query_disclose_option('g', &defquery);
930 list_genocided(defquery, ask);
933 if (!done_stopprint) {
934 ask = should_query_disclose_option('c', &defquery);
936 c = ask ? yn_function("Do you want to see your conduct?", ynqchars,
940 c = ask ? yn_function("
\82Ç
\82¤
\82¢
\82¤
\8ds
\93®
\82ð
\82Æ
\82Á
\82½
\82©
\8c©
\82Ü
\82·
\82©
\81H", ynqchars,
945 show_conduct((how >= PANICKED) ? 1 : 2);
950 if (!done_stopprint) {
951 ask = should_query_disclose_option('o', &defquery);
953 c = ask ? yn_function("Do you want to see the dungeon overview?",
957 c = ask ? yn_function("
\96À
\8b{
\82Ì
\8aT
\97v
\82ð
\8c©
\82Ü
\82·
\82©
\81H",
962 show_overview((how >= PANICKED) ? 1 : 2, how);
968 /* try to get the player back in a viable state after being killed */
973 int uhpmin = max(2 * u.ulevel, 10);
975 if (u.uhpmax < uhpmin)
979 if (u.uhunger < 500) {
983 /* cure impending doom of sickness hero won't have time to fix */
984 if ((Sick & TIMEOUT) == 1L) {
986 set_itimeout(&Sick, 0L);
991 nomovemsg = "You survived that attempt on your life.";
993 nomovemsg = "
\82 \82È
\82½
\82Í
\90¶
\82«
\82È
\82ª
\82ç
\82¦
\82½
\81D";
999 if (u.utrap && u.utraptype == TT_LAVA)
1002 u.ugrave_arise = NON_PM;
1005 if (!context.mon_moving)
1006 endmultishot(FALSE);
1010 * Get valuables from the given list. Revised code: the list always remains
1015 struct obj *list; /* inventory or container contents */
1017 register struct obj *obj;
1020 /* find amulets and gems, ignoring all artifacts */
1021 for (obj = list; obj; obj = obj->nobj)
1022 if (Has_contents(obj)) {
1023 get_valuables(obj->cobj);
1024 } else if (obj->oartifact) {
1026 } else if (obj->oclass == AMULET_CLASS) {
1027 i = obj->otyp - FIRST_AMULET;
1028 if (!amulets[i].count) {
1029 amulets[i].count = obj->quan;
1030 amulets[i].typ = obj->otyp;
1032 amulets[i].count += obj->quan; /* always adds one */
1033 } else if (obj->oclass == GEM_CLASS && obj->otyp < LUCKSTONE) {
1034 i = min(obj->otyp, LAST_GEM + 1) - FIRST_GEM;
1035 if (!gems[i].count) {
1036 gems[i].count = obj->quan;
1037 gems[i].typ = obj->otyp;
1039 gems[i].count += obj->quan;
1045 * Sort collected valuables, most frequent to least. We could just
1046 * as easily use qsort, but we don't care about efficiency here.
1049 sort_valuables(list, size)
1050 struct valuable_data list[];
1051 int size; /* max value is less than 20 */
1054 struct valuable_data ltmp;
1056 /* move greater quantities to the front of the list */
1057 for (i = 1; i < size; i++) {
1058 if (list[i].count == 0)
1059 continue; /* empty slot */
1060 ltmp = list[i]; /* structure copy */
1061 for (j = i; j > 0; --j)
1062 if (list[j - 1].count >= ltmp.count)
1065 list[j] = list[j - 1];
1075 odds_and_ends(list, what)
1080 for (otmp = list; otmp; otmp = otmp->nobj) {
1082 case CAT_CHECK: /* Schroedinger's Cat */
1083 /* Ascending is deterministic */
1084 if (SchroedingersBox(otmp))
1088 if (Has_contents(otmp))
1089 return odds_and_ends(otmp->cobj, what);
1094 /* called twice; first to calculate total, then to list relevant items */
1096 artifact_score(list, counting, endwin)
1098 boolean counting; /* true => add up points; false => display them */
1104 short dummy; /* object type returned by artifact_name() */
1106 for (otmp = list; otmp; otmp = otmp->nobj) {
1107 if (otmp->oartifact || otmp->otyp == BELL_OF_OPENING
1108 || otmp->otyp == SPE_BOOK_OF_THE_DEAD
1109 || otmp->otyp == CANDELABRUM_OF_INVOCATION) {
1110 value = arti_cost(otmp); /* zorkmid value */
1111 points = value * 5 / 2; /* score value */
1113 nowrap_add(u.urexp, points);
1115 makeknown(otmp->otyp);
1116 otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
1117 /* assumes artifacts don't have quan > 1 */
1119 Sprintf(pbuf, "%s%s (worth %ld %s and %ld points)",
1120 the_unique_obj(otmp) ? "The " : "",
1121 otmp->oartifact ? artifact_name(xname(otmp), &dummy)
1122 : OBJ_NAME(objects[otmp->otyp]),
1123 value, currency(value), points);
1125 Sprintf(pbuf, "%s(%ld%s
\81C%ld
\83|
\83C
\83\93\83g
\82Ì
\89¿
\92l)
\81C",
1126 otmp->oartifact ? artifact_name(xname(otmp), &dummy)
1127 : OBJ_NAME(objects[otmp->otyp]),
1128 value, currency(value), points);
1130 putstr(endwin, 0, pbuf);
1133 if (Has_contents(otmp))
1134 artifact_score(otmp->cobj, counting, endwin);
1138 /* Be careful not to call panic from here! */
1143 if (how == TRICKED) {
1144 if (killer.name[0]) {
1145 paniclog("trickery", killer.name);
1150 You("are a very tricky wizard, it seems.");
1152 You("
\82Æ
\82Ä
\82à
\88µ
\82¢
\82É
\82
\82¢wizard
\82Ì
\82æ
\82¤
\82¾
\81D");
1156 if (program_state.panicking
1157 #ifdef HANGUPHANDLING
1158 || program_state.done_hup
1161 /* skip status update if panicking or disconnected */
1162 context.botl = context.botlx = FALSE;
1164 /* otherwise force full status update */
1165 context.botlx = TRUE;
1169 if (how == ASCENDED || (!killer.name[0] && how == GENOCIDED))
1170 killer.format = NO_KILLER_PREFIX;
1171 /* Avoid killed by "a" burning or "a" starvation */
1172 if (!killer.name[0] && (how == STARVING || how == BURNING))
1173 killer.format = KILLED_BY;
1174 if (!killer.name[0] || how >= PANICKED)
1176 Strcpy(killer.name, deaths[how]);
1178 Strcpy(killer.name, ends[how]);
1182 if (Lifesaved && (how <= GENOCIDED)) {
1184 pline("But wait...");
1186 pline("
\82¿
\82å
\82Á
\82Æ
\82Ü
\82Á
\82½
\81D
\81D
\81D");
1187 makeknown(AMULET_OF_LIFE_SAVING);
1189 Your("medallion %s!", !Blind ? "begins to glow" : "feels warm");
1191 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½");
1196 You("
\93f
\82¢
\82½
\81D
\81D
\81D");
1198 You_feel("much better!");
1200 You("
\8bC
\95ª
\82ª
\82æ
\82
\82È
\82Á
\82½
\81I");
1202 pline_The("medallion crumbles to dust!");
1204 pline("
\96\82\8f\9c\82¯
\82Í
\82±
\82È
\82²
\82È
\82É
\82
\82¾
\82¯
\82½
\81I");
1208 (void) adjattrib(A_CON, -1, TRUE);
1210 if (how == GENOCIDED) {
1212 pline("Unfortunately you are still genocided...");
1214 pline("
\8ec
\94O
\82È
\82ª
\82ç
\81C
\82 \82È
\82½
\82Í
\8bs
\8eE
\82³
\82ê
\82½
\82Ü
\82Ü
\82¾
\81D
\81D
\81D");
1222 if ((wizard || discover) && (how <= GENOCIDED)
1223 && !paranoid_query(ParanoidDie, "Die?")) {
1225 if ((wizard || discover) && (how <= GENOCIDED)
1226 && !paranoid_query(ParanoidDie, "
\8e\80\82ñ
\82Å
\82Ý
\82é
\81H")) {
1229 pline("OK, so you don't %s.", (how == CHOKING) ? "choke" : "die");
1231 You("
\8e\80\82È
\82È
\82©
\82Á
\82½
\81D");
1240 /* separated from done() in order to specify the __noreturn__ attribute */
1247 winid endwin = WIN_ERR;
1248 boolean bones_ok, have_windows = iflags.window_inited;
1249 struct obj *corpse = (struct obj *) 0;
1255 * The game is now over...
1257 program_state.gameover = 1;
1258 /* in case of a subsequent panic(), there's no point trying to save */
1259 program_state.something_worth_saving = 0;
1260 /* render vision subsystem inoperative */
1261 iflags.vision_inited = 0;
1263 /* might have been killed while using a disposable item, so make sure
1264 it's gone prior to inventory disclosure and creation of bones data */
1266 /* maybe not on object lists; if an active light source, would cause
1267 big trouble (`obj_is_local' panic) for savebones() -> savelev() */
1268 if (thrownobj && thrownobj->where == OBJ_FREE)
1269 dealloc_obj(thrownobj);
1270 if (kickedobj && kickedobj->where == OBJ_FREE)
1271 dealloc_obj(kickedobj);
1273 /* remember time of death here instead of having bones, rip, and
1274 topten figure it out separately and possibly getting different
1275 time or even day if player is slow responding to --More-- */
1276 urealtime.finish_time = endtime = getnow();
1277 urealtime.realtime += (long) (endtime - urealtime.start_timing);
1279 dump_open_log(endtime);
1280 /* Sometimes you die on the first move. Life's not fair.
1281 * On those rare occasions you get hosed immediately, go out
1282 * smiling... :-) -3.
1284 if (moves <= 1 && how < PANICKED) /* You die... --More-- */
1286 pline("Do not pass go. Do not collect 200 %s.", currency(200L));
1288 pline("
\92\8d\88Ó
\88ê
\95b
\81C
\89ö
\89ä
\88ê
\90¶
\81C
\8e\80\96S
\88ê
\95à
\81D");
1291 wait_synch(); /* flush screen output */
1293 (void) signal(SIGINT, (SIG_RET_TYPE) done_intr);
1294 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
1295 (void) signal(SIGQUIT, (SIG_RET_TYPE) done_intr);
1296 sethanguphandler(done_hangup);
1298 #endif /* NO_SIGNAL */
1300 bones_ok = (how < GENOCIDED) && can_make_bones();
1302 if (bones_ok && launch_in_progress())
1303 force_launch_placement();
1305 /* maintain ugrave_arise even for !bones_ok */
1306 if (how == PANICKED)
1307 u.ugrave_arise = (NON_PM - 3); /* no corpse, no grave */
1308 else if (how == BURNING || how == DISSOLVED) /* corpse burns up too */
1309 u.ugrave_arise = (NON_PM - 2); /* leave no corpse */
1310 else if (how == STONING)
1311 u.ugrave_arise = (NON_PM - 1); /* statue instead of corpse */
1312 else if (how == TURNED_SLIME)
1313 u.ugrave_arise = PM_GREEN_SLIME;
1316 killer.format = NO_KILLER_PREFIX;
1319 u.umortality++; /* skipped above when how==QUIT */
1321 Strcpy(killer.name, "quit while already on Charon's boat");
1323 Strcpy(killer.name, "
\8eO
\93r
\82Ì
\90ì
\82Ì
\93n
\82µ
\91D
\82É
\8fæ
\82Á
\82Ä
\82¢
\82é
\8aÔ
\82É
\94²
\82¯
\82½");
1326 if (how == ESCAPED || how == PANICKED)
1327 killer.format = NO_KILLER_PREFIX;
1329 fixup_death(how); /* actually, fixup multi_reason */
1331 if (how != PANICKED) {
1332 /* these affect score and/or bones, but avoid them during panic */
1333 taken = paybill((how == ESCAPED) ? -1 : (how != QUIT));
1337 taken = FALSE; /* lint; assert( !bones_ok ); */
1342 display_nhwindow(WIN_MESSAGE, FALSE);
1344 if (how != PANICKED) {
1348 * This is needed for both inventory disclosure and dumplog.
1349 * Both are optional, so do it once here instead of duplicating
1350 * it in both of those places.
1352 for (obj = invent; obj; obj = obj->nobj) {
1353 makeknown(obj->otyp);
1354 obj->known = obj->bknown = obj->dknown = obj->rknown = 1;
1355 if (Is_container(obj) || obj->otyp == STATUE)
1356 obj->cknown = obj->lknown = 1;
1359 if (strcmp(flags.end_disclose, "none"))
1360 disclose(how, taken);
1362 dump_everything(how, endtime);
1365 /* if pets will contribute to score, populate mydogs list now
1366 (bones creation isn't a factor, but pline() messaging is; used to
1367 be done ever sooner, but we need it to come after dump_everything()
1368 so that any accompanying pets are still on the map during dump) */
1369 if (how == ESCAPED || how == ASCENDED)
1372 /* finish_paybill should be called after disclosure but before bones */
1373 if (bones_ok && taken)
1376 /* grave creation should be after disclosure so it doesn't have
1377 this grave in the current level's features for #overview */
1378 if (bones_ok && u.ugrave_arise == NON_PM
1379 && !(mvitals[u.umonnum].mvflags & G_NOCORPSE)) {
1380 int mnum = u.umonnum;
1383 /* Base corpse on race when not poly'd since original
1384 * u.umonnum is based on role, and all role monsters
1387 mnum = (flags.female && urace.femalenum != NON_PM)
1391 corpse = mk_named_object(CORPSE, &mons[mnum], u.ux, u.uy, plname);
1393 Sprintf(pbuf, "%s, ", plname);
1395 Sprintf(pbuf, "%s
\82Ì
\95æ
\81C", plname);
1396 formatkiller(eos(pbuf), sizeof pbuf - strlen(pbuf), how, TRUE);
1397 make_grave(u.ux, u.uy, pbuf);
1399 pbuf[0] = '\0'; /* clear grave text; also lint suppression */
1401 /* calculate score, before creating bones [container gold] */
1403 int deepest = deepest_lev_reached(FALSE);
1405 umoney = money_cnt(invent);
1407 umoney += hidden_gold(); /* accumulate gold from containers */
1408 tmp = umoney - tmp; /* net gain */
1414 tmp += 50L * (long) (deepest - 1);
1416 tmp += 1000L * (long) ((deepest > 30) ? 10 : deepest - 20);
1417 nowrap_add(u.urexp, tmp);
1419 /* ascension gives a score bonus iff offering to original deity */
1420 if (how == ASCENDED && u.ualign.type == u.ualignbase[A_ORIGINAL]) {
1421 /* retaining original alignment: score *= 2;
1422 converting, then using helm-of-OA to switch back: *= 1.5 */
1423 tmp = (u.ualignbase[A_CURRENT] == u.ualignbase[A_ORIGINAL])
1426 nowrap_add(u.urexp, tmp);
1430 if (u.ugrave_arise >= LOW_PM && u.ugrave_arise != PM_GREEN_SLIME) {
1431 /* give this feedback even if bones aren't going to be created,
1432 so that its presence or absence doesn't tip off the player to
1433 new bones or their lack; it might be a lie if makemon fails */
1435 Your("body rises from the dead as %s...",
1437 Your("
\91Ì
\82Í%s
\82Æ
\82µ
\82Ä
\8e\80\91Ì
\82©
\82ç
\91h
\82Á
\82½
\81D
\81D
\81D",
1438 an(mons[u.ugrave_arise].mname));
1439 display_nhwindow(WIN_MESSAGE, FALSE);
1444 if (!wizard || paranoid_query(ParanoidBones, "Save bones?"))
1446 if (!wizard || paranoid_query(ParanoidBones, "
\8d\9c\82ð
\82¤
\82ß
\82é
\81H"))
1447 savebones(how, endtime, corpse);
1448 /* corpse may be invalid pointer now so
1449 ensure that it isn't used again */
1450 corpse = (struct obj *) 0;
1453 /* update gold for the rip output, which can't use hidden_gold()
1454 (containers will be gone by then if bones just got saved...) */
1455 done_money = umoney;
1457 /* clean up unneeded windows */
1460 free_pickinv_cache(); /* extra persistent window if perm_invent */
1461 if (WIN_INVEN != WIN_ERR) {
1462 destroy_nhwindow(WIN_INVEN), WIN_INVEN = WIN_ERR;
1463 /* precaution in case any late update_inventory() calls occur */
1464 flags.perm_invent = 0;
1466 display_nhwindow(WIN_MESSAGE, TRUE);
1467 destroy_nhwindow(WIN_MAP), WIN_MAP = WIN_ERR;
1468 #ifndef STATUS_HILITES
1469 destroy_nhwindow(WIN_STATUS), WIN_STATUS = WIN_ERR;
1471 destroy_nhwindow(WIN_MESSAGE), WIN_MESSAGE = WIN_ERR;
1473 if (!done_stopprint || flags.tombstone)
1474 endwin = create_nhwindow(NHW_TEXT);
1476 if (how < GENOCIDED && flags.tombstone && endwin != WIN_ERR)
1477 outrip(endwin, how, endtime);
1479 done_stopprint = 1; /* just avoid any more output */
1482 /* 'how' reasons beyond genocide shouldn't show tombstone;
1483 for normal end of game, genocide doesn't either */
1484 if (how <= GENOCIDED) {
1485 dump_redirect(TRUE);
1486 if (iflags.in_dumplog)
1487 genl_outrip(0, how, endtime);
1488 dump_redirect(FALSE);
1491 if (u.uhave.amulet) {
1493 Strcat(killer.name, " (with the Amulet)");
1495 Strcat(killer.name, "
\96\82\8f\9c\82¯
\82ð
\8eè
\82É");
1496 } else if (how == ESCAPED) {
1497 if (Is_astralevel(&u.uz)) /* offered Amulet to wrong deity */
1499 Strcat(killer.name, " (in celestial disgrace)");
1501 Strcat(killer.name, "
\93V
\8fã
\82Å
\92p
\90J
\82ð
\8eó
\82¯
\92E
\8fo
\82µ
\82½");
1502 else if (carrying(FAKE_AMULET_OF_YENDOR))
1504 Strcat(killer.name, " (with a fake Amulet)");
1506 Strcat(killer.name, "
\8bU
\95¨
\82Ì
\96\82\8f\9c\82¯
\82ð
\92Í
\82Ü
\82³
\82ê
\92E
\8fo
\82µ
\82½");
1507 /* don't bother counting to see whether it should be plural */
1511 Sprintf(pbuf, "%s %s the %s...", Goodbye(), plname,
1513 ? (const char *) ((flags.female && urole.name.f)
1516 : (const char *) (flags.female ? "Demigoddess" : "Demigod"));
1518 Sprintf(pbuf, "%s%s
\82Ì%s
\81D
\81D
\81D", Goodbye(),
1520 ? (const char *) ((flags.female && urole.name.f)
1523 : (const char *) (flags.female ? "
\8f\97\90_" : "
\90_"),
1526 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1527 dump_forward_putstr(endwin, 0, "", done_stopprint);
1529 if (how == ESCAPED || how == ASCENDED) {
1532 register struct val_list *val;
1535 for (val = valuables; val->list; val++)
1536 for (i = 0; i < val->size; i++) {
1537 val->list[i].count = 0L;
1539 get_valuables(invent);
1541 /* add points for collected valuables */
1542 for (val = valuables; val->list; val++)
1543 for (i = 0; i < val->size; i++)
1544 if (val->list[i].count != 0L) {
1545 tmp = val->list[i].count
1546 * (long) objects[val->list[i].typ].oc_cost;
1547 nowrap_add(u.urexp, tmp);
1550 /* count the points for artifacts */
1551 artifact_score(invent, TRUE, endwin);
1553 viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */
1556 Strcpy(pbuf, "You");
1558 Strcpy(pbuf, "
\82 \82È
\82½");
1559 if (!Schroedingers_cat) /* check here in case disclosure was off */
1560 Schroedingers_cat = odds_and_ends(invent, CAT_CHECK);
1561 if (Schroedingers_cat) {
1562 int mhp, m_lev = adj_lev(&mons[PM_HOUSECAT]);
1565 nowrap_add(u.urexp, mhp);
1567 Strcat(eos(pbuf), " and Schroedinger's cat");
1569 Strcat(eos(pbuf), "
\82Æ
\83V
\83\85\83\8c\83f
\83B
\83\93\83K
\81[
\82Ì
\94L");
1574 Sprintf(eos(pbuf), " and %s", mon_nam(mtmp));
1576 Sprintf(eos(pbuf), "
\82Æ%s", mon_nam(mtmp));
1578 nowrap_add(u.urexp, mtmp->mhp);
1582 if (!done_stopprint)
1583 Strcat(pbuf, "
\82Í");
1585 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1591 Strcat(pbuf, "
\82Í");
1594 Sprintf(eos(pbuf), "%s with %ld point%s,",
1595 how == ASCENDED ? "went to your reward"
1596 : "escaped from the dungeon",
1597 u.urexp, plur(u.urexp));
1599 Sprintf(eos(pbuf), "%ld
\83|
\83C
\83\93\83g
\83}
\81[
\83N
\82µ%s
\81D",
1601 how==ASCENDED ? "
\8f¸
\93V
\82µ
\82½" : "
\96À
\8b{
\82©
\82ç
\92E
\8fo
\82µ
\82½");
1603 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1605 if (!done_stopprint)
1606 artifact_score(invent, FALSE, endwin); /* list artifacts */
1608 dump_redirect(TRUE);
1609 if (iflags.in_dumplog)
1610 artifact_score(invent, FALSE, 0);
1611 dump_redirect(FALSE);
1614 /* list valuables here */
1615 for (val = valuables; val->list; val++) {
1616 sort_valuables(val->list, val->size);
1617 for (i = 0; i < val->size && !done_stopprint; i++) {
1618 int typ = val->list[i].typ;
1619 long count = val->list[i].count;
1623 if (objects[typ].oc_class != GEM_CLASS || typ <= LAST_GEM) {
1624 otmp = mksobj(typ, FALSE, FALSE);
1625 makeknown(otmp->otyp);
1626 otmp->known = 1; /* for fake amulets */
1627 otmp->dknown = 1; /* seen it (blindness fix) */
1628 if (has_oname(otmp))
1632 Sprintf(pbuf, "%8ld %s (worth %ld %s),", count,
1633 xname(otmp), count * (long) objects[typ].oc_cost,
1636 Sprintf(pbuf, "%ld
\8cÂ
\82Ì%s(%ld%s
\82Ì
\89¿
\92l)
\81C", count,
1637 xname(otmp), count * (long) objects[typ].oc_cost,
1640 obfree(otmp, (struct obj *) 0);
1643 Sprintf(pbuf, "%8ld worthless piece%s of colored glass,",
1644 count, plur(count));
1646 Sprintf(pbuf, "%ld
\8cÂ
\82Ì
\89¿
\92l
\82Ì
\82È
\82¢
\90F
\82Â
\82«
\83K
\83\89\83X
\81C",
1650 dump_forward_putstr(endwin, 0, pbuf, 0);
1655 /* did not escape or ascend */
1656 if (u.uz.dnum == 0 && u.uz.dlevel <= 0) {
1657 /* level teleported out of the dungeon; `how' is DIED,
1658 due to falling or to "arriving at heaven prematurely" */
1660 Sprintf(pbuf, "You %s beyond the confines of the dungeon",
1661 (u.uz.dlevel < 0) ? "passed away" : ends[how]);
1663 Sprintf(pbuf, "
\96À
\8b{
\82Ì
\97Ì
\88æ
\82ð
\89z
\82¦%s
\81D",
1664 (u.uz.dlevel < 0) ? "
\8fÁ
\82¦
\82³
\82Á
\82½" : ends[how]);
1667 /* more conventional demise */
1668 const char *where = dungeons[u.uz.dnum].dname;
1670 if (Is_astralevel(&u.uz))
1672 where = "The Astral Plane";
1674 where = "
\90¸
\97ì
\8aE
\82É
\82Ä";
1676 Sprintf(pbuf, "You %s in %s", ends[how], where);
1678 Sprintf(pbuf, "
\82 \82È
\82½
\82Í%s", where);
1679 if (!In_endgame(&u.uz) && !Is_knox(&u.uz))
1681 Sprintf(eos(pbuf), " on dungeon level %d",
1682 In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz));
1684 Sprintf(eos(pbuf), "
\82Ì
\92n
\89º%d
\8aK
\82Å",
1685 In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz));
1690 Sprintf(eos(pbuf), " with %ld point%s,", u.urexp, plur(u.urexp));
1692 Sprintf(eos(pbuf), " %ld
\83|
\83C
\83\93\83g
\82ð
\83}
\81[
\83N
\82µ
\81C", u.urexp);
1693 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1697 Sprintf(pbuf, "and %ld piece%s of gold, after %ld move%s.", umoney,
1698 plur(umoney), moves, plur(moves));
1700 Sprintf(pbuf, "%ld
\96\87\82Ì
\8bà
\89Ý
\82ð
\8e\9d\82Á
\82Ä
\81C%ld
\95à
\93®
\82¢
\82½
\81D", umoney,
1703 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1706 "You were level %d with a maximum of %d hit point%s when you %s.",
1707 u.ulevel, u.uhpmax, plur(u.uhpmax), ends[how]);
1710 "%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",
1711 ends[how],u.ulevel, u.uhpmax);
1713 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1714 dump_forward_putstr(endwin, 0, "", done_stopprint);
1715 if (!done_stopprint)
1716 display_nhwindow(endwin, TRUE);
1717 if (endwin != WIN_ERR)
1718 destroy_nhwindow(endwin);
1721 /* "So when I die, the first thing I will see in Heaven is a
1723 if (have_windows && !iflags.toptenwin)
1724 exit_nhwindows((char *) 0), have_windows = FALSE;
1725 topten(how, endtime);
1727 exit_nhwindows((char *) 0);
1729 if (done_stopprint) {
1733 nh_terminate(EXIT_SUCCESS);
1737 container_contents(list, identified, all_containers, reportempty)
1739 boolean identified, all_containers, reportempty;
1741 register struct obj *box, *obj;
1743 boolean cat, deadcat;
1745 for (box = list; box; box = box->nobj) {
1746 if (Is_container(box) || box->otyp == STATUE) {
1747 box->cknown = 1; /* we're looking at the contents now */
1750 cat = deadcat = FALSE;
1751 if (SchroedingersBox(box) && !Schroedingers_cat) {
1752 /* Schroedinger's Cat? */
1753 cat = odds_and_ends(box, CAT_CHECK);
1755 Schroedingers_cat = TRUE;
1760 if (box->otyp == BAG_OF_TRICKS) {
1761 continue; /* wrong type of container */
1762 } else if (box->cobj) {
1763 winid tmpwin = create_nhwindow(NHW_MENU);
1765 sortloot(&box->cobj,
1766 (((flags.sortloot == 'l' || flags.sortloot == 'f')
1767 ? SORTLOOT_LOOT : 0)
1768 | (flags.sortpack ? SORTLOOT_PACK : 0)),
1771 Sprintf(buf, "Contents of %s:", the(xname(box)));
1773 Sprintf(buf, "%s
\82Ì
\92\86\90g
\81F", the(xname(box)));
1774 putstr(tmpwin, 0, buf);
1775 putstr(tmpwin, 0, "");
1776 for (obj = box->cobj; obj; obj = obj->nobj) {
1778 makeknown(obj->otyp);
1779 obj->known = obj->bknown = obj->dknown
1781 if (Is_container(obj) || obj->otyp == STATUE)
1782 obj->cknown = obj->lknown = 1;
1784 putstr(tmpwin, 0, doname(obj));
1788 putstr(tmpwin, 0, "Schroedinger's cat");
1790 putstr(tmpwin, 0, "
\83V
\83\85\83\8c\83f
\83B
\83\93\83K
\81[
\82Ì
\94L");
1793 putstr(tmpwin, 0, "Schroedinger's dead cat");
1795 putstr(tmpwin, 0, "
\83V
\83\85\83\8c\83f
\83B
\83\93\83K
\81[
\82Ì
\94L
\82Ì
\8e\80\91Ì");
1796 display_nhwindow(tmpwin, TRUE);
1797 destroy_nhwindow(tmpwin);
1799 container_contents(box->cobj, identified, TRUE,
1801 } else if (cat || deadcat) {
1803 pline("%s Schroedinger's %scat!", Tobjnam(box, "contain"),
1804 deadcat ? "dead " : "");
1806 pline("%s
\82É
\82Í
\83V
\83\85\83\8c\83f
\83B
\83\93\83K
\81[
\82Ì
\94L%s
\82ª
\93ü
\82Á
\82Ä
\82¢
\82½
\81I", xname(box),
1807 deadcat ? "
\82Ì
\8e\80\91Ì" : "");
1809 display_nhwindow(WIN_MESSAGE, FALSE);
1810 } else if (reportempty) {
1812 pline("%s is empty.", upstart(thesimpleoname(box)));
1814 pline("%s
\82Í
\8bó
\82Á
\82Û
\82¾
\81D", xname(box));
1815 display_nhwindow(WIN_MESSAGE, FALSE);
1818 if (!all_containers)
1823 /* should be called with either EXIT_SUCCESS or EXIT_FAILURE */
1825 nh_terminate(status)
1828 program_state.in_moveloop = 0; /* won't be returning to normal play */
1830 getreturn("to exit");
1832 /* don't bother to try to release memory if we're in panic mode, to
1833 avoid trouble in case that happens to be due to memory problems */
1834 if (!program_state.panicking) {
1841 * This is liable to draw a warning if compiled with gcc, but it's
1842 * more important to flag panic() -> really_done() -> nh_terminate()
1843 * as __noreturn__ then to avoid the warning.
1845 /* don't call exit() if already executing within an exit handler;
1846 that would cancel any other pending user-mode handlers */
1847 if (program_state.exiting)
1850 program_state.exiting = 1;
1852 jputchar('\0'); /* reset terminal */
1854 nethack_exit(status);
1857 extern const int monstr[];
1859 enum vanq_order_modes {
1869 NUM_VANQ_ORDER_MODES
1872 static const char *vanqorders[NUM_VANQ_ORDER_MODES] = {
1873 "traditional: by monster level, by internal monster index",
1874 "by monster toughness, by internal monster index",
1875 "alphabetically, first unique monsters, then others",
1876 "alphabetically, unique monsters and others intermixed",
1877 "by monster class, high to low level within class",
1878 "by monster class, low to high level within class",
1879 "by count, high to low, by internal index within tied count",
1880 "by count, low to high, by internal index within tied count",
1882 static int vanq_sortmode = VANQ_MLVL_MNDX;
1884 STATIC_PTR int CFDECLSPEC
1885 vanqsort_cmp(vptr1, vptr2)
1886 const genericptr vptr1;
1887 const genericptr vptr2;
1889 int indx1 = *(short *) vptr1, indx2 = *(short *) vptr2,
1890 mlev1, mlev2, mstr1, mstr2, uniq1, uniq2, died1, died2, res;
1891 const char *name1, *name2, *punct;
1894 switch (vanq_sortmode) {
1896 case VANQ_MLVL_MNDX:
1897 /* sort by monster level */
1898 mlev1 = mons[indx1].mlevel, mlev2 = mons[indx2].mlevel;
1899 res = mlev2 - mlev1; /* mlevel high to low */
1901 case VANQ_MSTR_MNDX:
1902 /* sort by monster toughness */
1903 mstr1 = monstr[indx1], mstr2 = monstr[indx2];
1904 res = mstr2 - mstr1; /* monstr high to low */
1906 case VANQ_ALPHA_SEP:
1907 uniq1 = ((mons[indx1].geno & G_UNIQ) && indx1 != PM_HIGH_PRIEST);
1908 uniq2 = ((mons[indx2].geno & G_UNIQ) && indx2 != PM_HIGH_PRIEST);
1909 if (uniq1 ^ uniq2) { /* one or other uniq, but not both */
1910 res = uniq2 - uniq1;
1912 } /* else both unique or neither unique */
1914 case VANQ_ALPHA_MIX:
1915 name1 = mons[indx1].mname, name2 = mons[indx2].mname;
1916 res = strcmpi(name1, name2); /* caseblind alhpa, low to high */
1918 case VANQ_MCLS_HTOL:
1919 case VANQ_MCLS_LTOH:
1920 /* mons[].mlet is a small integer, 1..N, of type plain char;
1921 if 'char' happens to be unsigned, (mlet1 - mlet2) would yield
1922 an inappropriate result when mlet2 is greater than mlet1,
1923 so force our copies (mcls1, mcls2) to be signed */
1924 mcls1 = (schar) mons[indx1].mlet, mcls2 = (schar) mons[indx2].mlet;
1925 /* S_ANT through S_ZRUTY correspond to lowercase monster classes,
1926 S_ANGEL through S_ZOMBIE correspond to uppercase, and various
1927 punctuation characters are used for classes beyond those */
1928 if (mcls1 > S_ZOMBIE && mcls2 > S_ZOMBIE) {
1929 /* force a specific order to the punctuation classes that's
1930 different from the internal order;
1931 internal order is ok if neither or just one is punctuation
1932 since letters have lower values so come out before punct */
1933 static const char punctclasses[] = {
1934 S_LIZARD, S_EEL, S_GOLEM, S_GHOST, S_DEMON, S_HUMAN, '\0'
1937 if ((punct = index(punctclasses, mcls1)) != 0)
1938 mcls1 = (schar) (S_ZOMBIE + 1 + (int) (punct - punctclasses));
1939 if ((punct = index(punctclasses, mcls2)) != 0)
1940 mcls2 = (schar) (S_ZOMBIE + 1 + (int) (punct - punctclasses));
1942 res = mcls1 - mcls2; /* class */
1944 mlev1 = mons[indx1].mlevel, mlev2 = mons[indx2].mlevel;
1945 res = mlev1 - mlev2; /* mlevel low to high */
1946 if (vanq_sortmode == VANQ_MCLS_HTOL)
1947 res = -res; /* mlevel high to low */
1950 case VANQ_COUNT_H_L:
1951 case VANQ_COUNT_L_H:
1952 died1 = mvitals[indx1].died, died2 = mvitals[indx2].died;
1953 res = died2 - died1; /* dead count high to low */
1954 if (vanq_sortmode == VANQ_COUNT_L_H)
1955 res = -res; /* dead count low to high */
1958 /* tiebreaker: internal mons[] index */
1960 res = indx1 - indx2; /* mndx low to high */
1964 /* returns -1 if cancelled via ESC */
1969 menu_item *selected;
1973 tmpwin = create_nhwindow(NHW_MENU);
1975 any = zeroany; /* zero out all bits */
1976 for (i = 0; i < SIZE(vanqorders); i++) {
1977 if (i == VANQ_ALPHA_MIX || i == VANQ_MCLS_HTOL) /* skip these */
1980 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, vanqorders[i],
1981 (i == vanq_sortmode) ? MENU_SELECTED : MENU_UNSELECTED);
1983 end_menu(tmpwin, "Sort order for vanquished monster counts");
1985 n = select_menu(tmpwin, PICK_ONE, &selected);
1986 destroy_nhwindow(tmpwin);
1988 choice = selected[0].item.a_int - 1;
1989 /* skip preselected entry if we have more than one item chosen */
1990 if (n > 1 && choice == vanq_sortmode)
1991 choice = selected[1].item.a_int - 1;
1992 free((genericptr_t) selected);
1993 vanq_sortmode = choice;
1995 return (n < 0) ? -1 : vanq_sortmode;
1998 /* #vanquished command */
2002 list_vanquished('a', FALSE);
2006 /* high priests aren't unique but are flagged as such to simplify something */
2007 #define UniqCritterIndx(mndx) ((mons[mndx].geno & G_UNIQ) \
2008 && mndx != PM_HIGH_PRIEST)
2011 list_vanquished(defquery, ask)
2017 unsigned ntypes, ni;
2018 long total_killed = 0L;
2020 short mindx[NUMMONS];
2021 char c, buf[BUFSZ], buftoo[BUFSZ];
2022 boolean dumping; /* for DUMPLOG; doesn't need to be conditional */
2024 dumping = (defquery == 'd');
2028 /* get totals first */
2030 for (i = LOW_PM; i < NUMMONS; i++) {
2031 if ((nkilled = (int) mvitals[i].died) == 0)
2033 mindx[ntypes++] = i;
2034 total_killed += (long) nkilled;
2037 /* vanquished creatures list;
2038 * includes all dead monsters, not just those killed by the player
2041 char mlet, prev_mlet = 0; /* used as small integer, not character */
2042 boolean class_header, uniq_header, was_uniq = FALSE;
2045 c = ask ? yn_function(
2046 "Do you want an account of creatures vanquished?",
2047 ynaqchars, defquery)
2050 c = ask ? yn_function(
2051 "
\93|
\82µ
\82½
\93G
\82Ì
\88ê
\97\97\82ð
\8c©
\82Ü
\82·
\82©
\81H",
2057 if (c == 'y' || c == 'a') {
2058 if (c == 'a') { /* ask player to choose sort order */
2059 /* choose value for vanq_sortmode via menu; ESC cancels list
2060 of vanquished monsters but does not set 'done_stopprint' */
2061 if (set_vanq_order() < 0)
2064 uniq_header = (vanq_sortmode == VANQ_ALPHA_SEP);
2065 class_header = (vanq_sortmode == VANQ_MCLS_LTOH
2066 || vanq_sortmode == VANQ_MCLS_HTOL);
2068 klwin = create_nhwindow(NHW_MENU);
2070 putstr(klwin, 0, "Vanquished creatures:");
2072 putstr(klwin, 0, "
\93|
\82µ
\82½
\93G
\81F");
2074 putstr(klwin, 0, "");
2076 qsort((genericptr_t) mindx, ntypes, sizeof *mindx, vanqsort_cmp);
2077 for (ni = 0; ni < ntypes; ni++) {
2079 nkilled = mvitals[i].died;
2080 mlet = mons[i].mlet;
2081 if (class_header && mlet != prev_mlet) {
2082 Strcpy(buf, def_monsyms[(int) mlet].explain);
2083 putstr(klwin, ask ? 0 : iflags.menu_headings,
2087 if (UniqCritterIndx(i)) {
2089 Sprintf(buf, "%s%s",
2090 !type_is_pname(&mons[i]) ? "the " : "",
2093 Sprintf(buf, "%s", mons[i].mname);
2099 Sprintf(eos(buf), " (twice)");
2102 Sprintf(eos(buf), " (thrice)");
2105 Sprintf(eos(buf), " (%d times)", nkilled);
2109 Sprintf(eos(buf)," (%d
\89ñ)", nkilled);
2114 if (uniq_header && was_uniq) {
2115 putstr(klwin, 0, "");
2118 /* trolls or undead might have come back,
2119 but we don't keep track of that */
2121 Strcpy(buf, an(mons[i].mname));
2124 Sprintf(buf, "%3d %s", nkilled,
2125 makeplural(mons[i].mname));
2127 Sprintf(buf, "%d
\91Ì
\82Ì%s", nkilled,
2131 /* number of leading spaces to match 3 digit prefix */
2132 pfx = !strncmpi(buf, "the ", 3) ? 0
2133 : !strncmpi(buf, "an ", 3) ? 1
2134 : !strncmpi(buf, "a ", 2) ? 2
2135 : !digit(buf[2]) ? 4 : 0;
2138 Sprintf(buftoo, "%*s%s", pfx, "", buf);
2139 putstr(klwin, 0, buftoo);
2142 * if (Hallucination)
2143 * putstr(klwin, 0, "and a partridge in a pear tree");
2147 putstr(klwin, 0, "");
2149 Sprintf(buf, "%ld creatures vanquished.", total_killed);
2151 Sprintf(buf, "%ld
\95C
\82Ì
\93G
\82ð
\93|
\82µ
\82½
\81D", total_killed);
2152 putstr(klwin, 0, buf);
2154 display_nhwindow(klwin, TRUE);
2155 destroy_nhwindow(klwin);
2157 } else if (defquery == 'a') {
2158 /* #dovanquished rather than final disclosure, so pline() is ok */
2160 pline("No creatures have been vanquished.");
2162 pline("
\93|
\82µ
\82½
\93G
\82Í
\82¢
\82È
\82©
\82Á
\82½
\81D");
2164 } else if (dumping) {
2165 putstr(0, 0, "No creatures were vanquished."); /* not pline() */
2170 /* number of monster species which have been genocided */
2176 for (i = LOW_PM; i < NUMMONS; ++i) {
2177 if (mvitals[i].mvflags & G_GENOD) {
2179 if (UniqCritterIndx(i))
2180 impossible("unique creature '%d: %s' genocided?",
2192 for (i = LOW_PM; i < NUMMONS; ++i) {
2193 if (UniqCritterIndx(i))
2195 if ((mvitals[i].mvflags & G_GONE) == G_EXTINCT)
2202 list_genocided(defquery, ask)
2207 int ngenocided, nextinct;
2211 boolean dumping; /* for DUMPLOG; doesn't need to be conditional */
2213 dumping = (defquery == 'd');
2217 ngenocided = num_genocides();
2218 nextinct = num_extinct();
2220 /* genocided or extinct species list */
2221 if (ngenocided != 0 || nextinct != 0) {
2223 Sprintf(buf, "Do you want a list of %sspecies%s%s?",
2224 (nextinct && !ngenocided) ? "extinct " : "",
2225 (ngenocided) ? " genocided" : "",
2226 (nextinct && ngenocided) ? " and extinct" : "");
2228 Sprintf(buf, "%s%s%s
\82µ
\82½
\8eí
\82Ì
\88ê
\97\97\82ð
\8c©
\82Ü
\82·
\82©
\81H",
2229 (nextinct && !ngenocided) ? "
\90â
\96Å" : "",
2230 (ngenocided) ? "
\8bs
\8eE" : "",
2231 (nextinct && ngenocided) ? "
\82¨
\82æ
\82Ñ
\90â
\96Å" : "");
2233 c = ask ? yn_function(buf, ynqchars, defquery) : defquery;
2237 klwin = create_nhwindow(NHW_MENU);
2239 Sprintf(buf, "%s%s species:",
2240 (ngenocided) ? "Genocided" : "Extinct",
2241 (nextinct && ngenocided) ? " or extinct" : "");
2243 Sprintf(buf, "%s%s
\82µ
\82½
\8eí:",
2244 (ngenocided) ? "
\8bs
\8eE" : "
\90â
\96Å",
2245 (nextinct && ngenocided) ? "
\82Ü
\82½
\82Í
\90â
\96Å" : "");
2247 putstr(klwin, 0, buf);
2249 putstr(klwin, 0, "");
2251 for (i = LOW_PM; i < NUMMONS; i++) {
2252 /* uniques can't be genocided but can become extinct;
2253 however, they're never reported as extinct, so skip them */
2254 if (UniqCritterIndx(i))
2256 if (mvitals[i].mvflags & G_GONE) {
2257 Sprintf(buf, " %s", makeplural(mons[i].mname));
2259 * "Extinct" is unfortunate terminology. A species
2260 * is marked extinct when its birth limit is reached,
2261 * but there might be members of the species still
2262 * alive, contradicting the meaning of the word.
2264 if ((mvitals[i].mvflags & G_GONE) == G_EXTINCT)
2266 Strcat(buf, " (extinct)");
2268 Strcat(buf, "(
\90â
\96Å)");
2269 putstr(klwin, 0, buf);
2273 putstr(klwin, 0, "");
2274 if (ngenocided > 0) {
2276 Sprintf(buf, "%d species genocided.", ngenocided);
2278 Sprintf(buf, "%d
\8eí
\97Þ
\82Ì
\8eí
\82ð
\8bs
\8eE
\82µ
\82½
\81D", ngenocided);
2279 putstr(klwin, 0, buf);
2283 Sprintf(buf, "%d species extinct.", nextinct);
2285 Sprintf(buf, "%d
\8eí
\97Þ
\82Ì
\8eí
\82ð
\90â
\96Å
\82³
\82¹
\82½
\81D", nextinct);
2286 putstr(klwin, 0, buf);
2289 display_nhwindow(klwin, TRUE);
2290 destroy_nhwindow(klwin);
2293 } else if (dumping) {
2294 putstr(0, 0, "No species were genocided or became extinct.");
2299 /* set a delayed killer, ensure non-delayed killer is cleared out */
2301 delayed_killer(id, format, killername)
2304 const char *killername;
2306 struct kinfo *k = find_delayed_killer(id);
2308 if (k == (struct kinfo *) 0) {
2309 /* no match, add a new delayed killer to the list */
2310 k = (struct kinfo *) alloc(sizeof(struct kinfo));
2311 (void) memset((genericptr_t)k, 0, sizeof(struct kinfo));
2313 k->next = killer.next;
2318 Strcpy(k->name, killername ? killername : "");
2323 find_delayed_killer(id)
2328 for (k = killer.next; k != (struct kinfo *) 0; k = k->next) {
2336 dealloc_killer(kptr)
2339 struct kinfo *prev = &killer, *k;
2341 if (kptr == (struct kinfo *) 0)
2343 for (k = killer.next; k != (struct kinfo *) 0; k = k->next) {
2349 if (k == (struct kinfo *) 0) {
2350 impossible("dealloc_killer not on list");
2352 prev->next = k->next;
2353 free((genericptr_t) k);
2358 save_killers(fd, mode)
2364 if (perform_bwrite(mode)) {
2365 for (kptr = &killer; kptr != (struct kinfo *) 0; kptr = kptr->next) {
2366 bwrite(fd, (genericptr_t) kptr, sizeof(struct kinfo));
2369 if (release_data(mode)) {
2370 while (killer.next) {
2371 kptr = killer.next->next;
2372 free((genericptr_t) killer.next);
2384 for (kptr = &killer; kptr != (struct kinfo *) 0; kptr = kptr->next) {
2385 mread(fd, (genericptr_t) kptr, sizeof(struct kinfo));
2387 kptr->next = (struct kinfo *) alloc(sizeof(struct kinfo));
2399 while (*p && isspace((uchar) *p))
2403 while (*p && !isspace((uchar) *p))
2415 out += strlen(out); /* eos() */
2416 while (*in && isspace((uchar) *in))
2418 while (*in && !isspace((uchar) *in))
2425 build_english_list(in)
2429 int len = (int) strlen(p), words = wordcount(p);
2431 /* +3: " or " - " "; +(words - 1): (N-1)*(", " - " ") */
2433 len += 3 + (words - 1);
2434 out = (char *) alloc(len + 1);
2435 *out = '\0'; /* bel_copy1() appends */
2439 impossible("no words in list");
2447 /* "first or second" */
2451 /* "first, second, or third */
2455 } while (--words > 1);