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 #if 0 /*JP*//*
\93ú
\96{
\8cê
\82Å
\82Í
\8eg
\82í
\82È
\82¢*/
594 static const struct {
596 const char *exclude, *include;
598 /* "petrified by <foo>, while getting stoned" -- "while getting stoned"
599 prevented any last-second recovery, but it was not the cause of
600 "petrified by <foo>" */
601 { STONING, 1, "getting stoned", (char *) 0 },
602 /* "died of starvation, while fainted from lack of food" is accurate
603 but sounds a fairly silly (and doesn't actually appear unless you
604 splice together death and while-helpless from xlogfile) */
605 { STARVING, 0, "fainted from lack of food", "fainted" },
608 /* clear away while-helpless when the cause of death caused that
609 helplessness (ie, "petrified by <foo> while getting stoned") */
617 for (i = 0; i < SIZE(death_fixups); ++i)
618 if (death_fixups[i].why == how
619 && !strcmp(death_fixups[i].exclude, multi_reason)) {
620 if (death_fixups[i].include) /* substitute alternate reason */
621 multi_reason = death_fixups[i].include;
622 else /* remove the helplessness reason */
623 multi_reason = (char *) 0;
624 if (death_fixups[i].unmulti) /* possibly hide helplessness */
632 #if defined(WIN32) && !defined(SYSCF)
633 #define NOTIFY_NETHACK_BUGS
638 VA_DECL(const char *, str)
641 VA_INIT(str, char *);
643 if (program_state.panicking++)
644 NH_abort(); /* avoid loops - this should never happen*/
646 if (iflags.window_inited) {
647 raw_print("\r\nOops...");
648 wait_synch(); /* make sure all pending output gets flushed */
649 exit_nhwindows((char *) 0);
650 iflags.window_inited = 0; /* they're gone; force raw_print()ing */
653 raw_print(program_state.gameover
655 ? "Postgame wrapup disrupted."
657 ? "
\83Q
\81[
\83\80\8fI
\97¹
\8e\9e\82Ì
\8f\88\97\9d\82ª
\95ö
\89ó
\82µ
\82½
\81D"
658 : !program_state.something_worth_saving
660 ? "Program initialization has failed."
662 ? "
\83v
\83\8d\83O
\83\89\83\80\82Ì
\8f\89\8aú
\89»
\82É
\8e¸
\94s
\82µ
\82½
\81D"
664 : "Suddenly, the dungeon collapses.");
666 : "
\93Ë
\91R
\96À
\8b{
\82ª
\95ö
\82ê
\82½
\81D");
668 #if defined(NOTIFY_NETHACK_BUGS)
670 raw_printf("Report the following error to \"%s\" or at \"%s\".",
671 DEVTEAM_EMAIL, DEVTEAM_URL);
672 else if (program_state.something_worth_saving)
673 raw_print("\nError save file being written.\n");
677 const char *maybe_rebuild = !program_state.something_worth_saving
679 : "\nand it may be possible to rebuild.";
681 const char *maybe_rebuild = !program_state.something_worth_saving
683 : "\n
\95\9c\8b\8c\82Å
\82«
\82é
\89Â
\94\
\90«
\82ª
\82 \82è
\82Ü
\82·
\81D";
687 raw_printf("To report this error, %s%s", sysopt.support,
689 else if (sysopt.fmtd_wizard_list) /* formatted SYSCF WIZARDS */
690 raw_printf("To report this error, contact %s%s",
691 sysopt.fmtd_wizard_list, maybe_rebuild);
694 raw_printf("Report error to \"%s\"%s", WIZARD_NAME,
697 raw_printf("\"%s\"
\82É
\83G
\83\89\81[
\82ð
\95ñ
\8d\90\82µ
\82Ä
\82
\82¾
\82³
\82¢
\81D%s", WIZARD_NAME,
702 /* XXX can we move this above the prints? Then we'd be able to
703 * suppress "it may be possible to rebuild" based on dosave0()
704 * or say it's NOT possible to rebuild. */
705 if (program_state.something_worth_saving) {
706 set_error_savefile();
708 /* os/win port specific recover instructions */
710 raw_printf("%s", sysopt.recover);
717 Vsprintf(buf, str, VA_ARGS);
719 paniclog("panic", buf);
722 interject(INTERJECT_PANIC);
724 #if defined(UNIX) || defined(VMS) || defined(LATTICE) || defined(WIN32)
726 NH_abort(); /* generate core dump */
729 really_done(PANICKED);
733 should_query_disclose_option(category, defquery)
741 if ((dop = index(disclosure_options, category)) != 0) {
742 idx = (int) (dop - disclosure_options);
743 if (idx < 0 || idx >= NUM_DISCLOSURE_OPTIONS) {
745 "should_query_disclose_option: bad disclosure index %d %c",
747 *defquery = DISCLOSE_PROMPT_DEFAULT_YES;
750 disclose = flags.end_disclose[idx];
751 if (disclose == DISCLOSE_YES_WITHOUT_PROMPT) {
754 } else if (disclose == DISCLOSE_SPECIAL_WITHOUT_PROMPT) {
757 } else if (disclose == DISCLOSE_NO_WITHOUT_PROMPT) {
760 } else if (disclose == DISCLOSE_PROMPT_DEFAULT_YES) {
763 } else if (disclose == DISCLOSE_PROMPT_DEFAULT_SPECIAL) {
771 impossible("should_query_disclose_option: bad category %c", category);
780 char buf[BUFSZ], **strp;
781 extern char *saved_plines[];
782 extern unsigned saved_pline_index;
784 Strcpy(buf, " "); /* one space for indentation */
785 putstr(0, 0, "Latest messages:");
786 for (i = 0, j = (int) saved_pline_index; i < DUMPLOG_MSG_COUNT;
787 ++i, j = (j + 1) % DUMPLOG_MSG_COUNT) {
788 strp = &saved_plines[j];
790 copynchars(&buf[1], *strp, BUFSZ - 1 - 1);
792 #ifdef FREE_ALL_MEMORY
793 free(*strp), *strp = 0;
802 dump_everything(how, when)
804 time_t when; /* date+time at end of game */
807 char pbuf[BUFSZ], datetimebuf[24]; /* [24]: room for 64-bit bogus value */
810 if (!iflags.in_dumplog)
813 init_symbols(); /* revert to default symbol set */
815 /* one line version ID, which includes build date+time;
816 it's conceivable that the game started with a different
817 build date+time or even with an older nethack version,
818 but we only have access to the one it finished under */
819 putstr(0, 0, getversionstring(pbuf));
822 /* game start and end date+time to disambiguate version date+time */
823 Strcpy(datetimebuf, yyyymmddhhmmss(ubirthday));
824 Sprintf(pbuf, "Game began %4.4s-%2.2s-%2.2s %2.2s:%2.2s:%2.2s",
825 &datetimebuf[0], &datetimebuf[4], &datetimebuf[6],
826 &datetimebuf[8], &datetimebuf[10], &datetimebuf[12]);
827 Strcpy(datetimebuf, yyyymmddhhmmss(when));
828 Sprintf(eos(pbuf), ", ended %4.4s-%2.2s-%2.2s %2.2s:%2.2s:%2.2s.",
829 &datetimebuf[0], &datetimebuf[4], &datetimebuf[6],
830 &datetimebuf[8], &datetimebuf[10], &datetimebuf[12]);
834 /* character name and basic role info */
835 Sprintf(pbuf, "%s, %s %s %s %s", plname,
836 aligns[1 - u.ualign.type].adj,
837 genders[flags.female].adj,
839 (flags.female && urole.name.f) ? urole.name.f : urole.name.m);
844 putstr(0, 0, do_statusline1());
845 putstr(0, 0, do_statusline2());
850 putstr(0, 0, "Inventory:");
851 display_inventory((char *) 0, TRUE);
852 container_contents(invent, TRUE, TRUE, FALSE);
853 enlightenment((BASICENLIGHTENMENT | MAGICENLIGHTENMENT),
854 (how >= PANICKED) ? ENL_GAMEOVERALIVE : ENL_GAMEOVERDEAD);
856 list_vanquished('d', FALSE); /* 'd' => 'y' */
858 list_genocided('d', FALSE); /* 'd' => 'y' */
860 show_conduct((how >= PANICKED) ? 1 : 2);
862 show_overview((how >= PANICKED) ? 1 : 2, how);
864 dump_redirect(FALSE);
876 char c = '\0', defquery;
880 if (invent && !done_stopprint) {
883 Sprintf(qbuf, "Do you want to see what you had when you %s?",
884 (how == QUIT) ? "quit" : "died");
886 Sprintf(qbuf,"%s
\82Æ
\82«
\89½
\82ð
\8e\9d\82Á
\82Ä
\82¢
\82½
\82©
\8c©
\82Ü
\82·
\82©
\81H",
887 (how == QUIT) ? "
\82â
\82ß
\82½" : "
\8e\80\82ñ
\82¾");
891 Strcpy(qbuf, "Do you want your possessions identified?");
893 Strcpy(qbuf,"
\8e\9d\82¿
\95¨
\82ð
\8e¯
\95Ê
\82µ
\82Ü
\82·
\82©
\81H");
895 ask = should_query_disclose_option('i', &defquery);
896 c = ask ? yn_function(qbuf, ynqchars, defquery) : defquery;
898 /* caller has already ID'd everything */
899 (void) display_inventory((char *) 0, TRUE);
900 container_contents(invent, TRUE, TRUE, FALSE);
906 if (!done_stopprint) {
907 ask = should_query_disclose_option('a', &defquery);
909 c = ask ? yn_function("Do you want to see your attributes?", ynqchars,
913 c = ask ? yn_function("
\91®
\90«
\82ð
\8c©
\82Ü
\82·
\82©
\81H", ynqchars,
918 enlightenment((BASICENLIGHTENMENT | MAGICENLIGHTENMENT),
919 (how >= PANICKED) ? ENL_GAMEOVERALIVE
925 if (!done_stopprint) {
926 ask = should_query_disclose_option('v', &defquery);
927 list_vanquished(defquery, ask);
930 if (!done_stopprint) {
931 ask = should_query_disclose_option('g', &defquery);
932 list_genocided(defquery, ask);
935 if (!done_stopprint) {
936 ask = should_query_disclose_option('c', &defquery);
938 c = ask ? yn_function("Do you want to see your conduct?", ynqchars,
942 c = ask ? yn_function("
\82Ç
\82¤
\82¢
\82¤
\8ds
\93®
\82ð
\82Æ
\82Á
\82½
\82©
\8c©
\82Ü
\82·
\82©
\81H", ynqchars,
947 show_conduct((how >= PANICKED) ? 1 : 2);
952 if (!done_stopprint) {
953 ask = should_query_disclose_option('o', &defquery);
955 c = ask ? yn_function("Do you want to see the dungeon overview?",
959 c = ask ? yn_function("
\96À
\8b{
\82Ì
\8aT
\97v
\82ð
\8c©
\82Ü
\82·
\82©
\81H",
964 show_overview((how >= PANICKED) ? 1 : 2, how);
970 /* try to get the player back in a viable state after being killed */
975 int uhpmin = max(2 * u.ulevel, 10);
977 if (u.uhpmax < uhpmin)
981 if (u.uhunger < 500) {
985 /* cure impending doom of sickness hero won't have time to fix */
986 if ((Sick & TIMEOUT) == 1L) {
988 set_itimeout(&Sick, 0L);
993 nomovemsg = "You survived that attempt on your life.";
995 nomovemsg = "
\82 \82È
\82½
\82Í
\90¶
\82«
\82È
\82ª
\82ç
\82¦
\82½
\81D";
1001 if (u.utrap && u.utraptype == TT_LAVA)
1004 u.ugrave_arise = NON_PM;
1007 if (!context.mon_moving)
1008 endmultishot(FALSE);
1012 * Get valuables from the given list. Revised code: the list always remains
1017 struct obj *list; /* inventory or container contents */
1019 register struct obj *obj;
1022 /* find amulets and gems, ignoring all artifacts */
1023 for (obj = list; obj; obj = obj->nobj)
1024 if (Has_contents(obj)) {
1025 get_valuables(obj->cobj);
1026 } else if (obj->oartifact) {
1028 } else if (obj->oclass == AMULET_CLASS) {
1029 i = obj->otyp - FIRST_AMULET;
1030 if (!amulets[i].count) {
1031 amulets[i].count = obj->quan;
1032 amulets[i].typ = obj->otyp;
1034 amulets[i].count += obj->quan; /* always adds one */
1035 } else if (obj->oclass == GEM_CLASS && obj->otyp < LUCKSTONE) {
1036 i = min(obj->otyp, LAST_GEM + 1) - FIRST_GEM;
1037 if (!gems[i].count) {
1038 gems[i].count = obj->quan;
1039 gems[i].typ = obj->otyp;
1041 gems[i].count += obj->quan;
1047 * Sort collected valuables, most frequent to least. We could just
1048 * as easily use qsort, but we don't care about efficiency here.
1051 sort_valuables(list, size)
1052 struct valuable_data list[];
1053 int size; /* max value is less than 20 */
1056 struct valuable_data ltmp;
1058 /* move greater quantities to the front of the list */
1059 for (i = 1; i < size; i++) {
1060 if (list[i].count == 0)
1061 continue; /* empty slot */
1062 ltmp = list[i]; /* structure copy */
1063 for (j = i; j > 0; --j)
1064 if (list[j - 1].count >= ltmp.count)
1067 list[j] = list[j - 1];
1077 odds_and_ends(list, what)
1082 for (otmp = list; otmp; otmp = otmp->nobj) {
1084 case CAT_CHECK: /* Schroedinger's Cat */
1085 /* Ascending is deterministic */
1086 if (SchroedingersBox(otmp))
1090 if (Has_contents(otmp))
1091 return odds_and_ends(otmp->cobj, what);
1096 /* called twice; first to calculate total, then to list relevant items */
1098 artifact_score(list, counting, endwin)
1100 boolean counting; /* true => add up points; false => display them */
1106 short dummy; /* object type returned by artifact_name() */
1108 for (otmp = list; otmp; otmp = otmp->nobj) {
1109 if (otmp->oartifact || otmp->otyp == BELL_OF_OPENING
1110 || otmp->otyp == SPE_BOOK_OF_THE_DEAD
1111 || otmp->otyp == CANDELABRUM_OF_INVOCATION) {
1112 value = arti_cost(otmp); /* zorkmid value */
1113 points = value * 5 / 2; /* score value */
1115 nowrap_add(u.urexp, points);
1117 makeknown(otmp->otyp);
1118 otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
1119 /* assumes artifacts don't have quan > 1 */
1121 Sprintf(pbuf, "%s%s (worth %ld %s and %ld points)",
1122 the_unique_obj(otmp) ? "The " : "",
1123 otmp->oartifact ? artifact_name(xname(otmp), &dummy)
1124 : OBJ_NAME(objects[otmp->otyp]),
1125 value, currency(value), points);
1127 Sprintf(pbuf, "%s(%ld%s
\81C%ld
\83|
\83C
\83\93\83g
\82Ì
\89¿
\92l)
\81C",
1128 otmp->oartifact ? artifact_name(xname(otmp), &dummy)
1129 : OBJ_NAME(objects[otmp->otyp]),
1130 value, currency(value), points);
1132 putstr(endwin, 0, pbuf);
1135 if (Has_contents(otmp))
1136 artifact_score(otmp->cobj, counting, endwin);
1140 /* Be careful not to call panic from here! */
1145 if (how == TRICKED) {
1146 if (killer.name[0]) {
1147 paniclog("trickery", killer.name);
1152 You("are a very tricky wizard, it seems.");
1154 You("
\82Æ
\82Ä
\82à
\88µ
\82¢
\82É
\82
\82¢wizard
\82Ì
\82æ
\82¤
\82¾
\81D");
1158 if (program_state.panicking
1159 #ifdef HANGUPHANDLING
1160 || program_state.done_hup
1163 /* skip status update if panicking or disconnected */
1164 context.botl = context.botlx = FALSE;
1166 /* otherwise force full status update */
1167 context.botlx = TRUE;
1171 if (how == ASCENDED || (!killer.name[0] && how == GENOCIDED))
1172 killer.format = NO_KILLER_PREFIX;
1173 /* Avoid killed by "a" burning or "a" starvation */
1174 if (!killer.name[0] && (how == STARVING || how == BURNING))
1175 killer.format = KILLED_BY;
1176 if (!killer.name[0] || how >= PANICKED)
1178 Strcpy(killer.name, deaths[how]);
1180 Strcpy(killer.name, ends[how]);
1184 if (Lifesaved && (how <= GENOCIDED)) {
1186 pline("But wait...");
1188 pline("
\82¿
\82å
\82Á
\82Æ
\82Ü
\82Á
\82½
\81D
\81D
\81D");
1189 makeknown(AMULET_OF_LIFE_SAVING);
1191 Your("medallion %s!", !Blind ? "begins to glow" : "feels warm");
1193 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½");
1198 You("
\93f
\82¢
\82½
\81D
\81D
\81D");
1200 You_feel("much better!");
1202 You("
\8bC
\95ª
\82ª
\82æ
\82
\82È
\82Á
\82½
\81I");
1204 pline_The("medallion crumbles to dust!");
1206 pline("
\96\82\8f\9c\82¯
\82Í
\82±
\82È
\82²
\82È
\82É
\82
\82¾
\82¯
\82½
\81I");
1210 (void) adjattrib(A_CON, -1, TRUE);
1212 if (how == GENOCIDED) {
1214 pline("Unfortunately you are still genocided...");
1216 pline("
\8ec
\94O
\82È
\82ª
\82ç
\81C
\82 \82È
\82½
\82Í
\8bs
\8eE
\82³
\82ê
\82½
\82Ü
\82Ü
\82¾
\81D
\81D
\81D");
1224 if ((wizard || discover) && (how <= GENOCIDED)
1225 && !paranoid_query(ParanoidDie, "Die?")) {
1227 if ((wizard || discover) && (how <= GENOCIDED)
1228 && !paranoid_query(ParanoidDie, "
\8e\80\82ñ
\82Å
\82Ý
\82é
\81H")) {
1231 pline("OK, so you don't %s.", (how == CHOKING) ? "choke" : "die");
1233 You("
\8e\80\82È
\82È
\82©
\82Á
\82½
\81D");
1242 /* separated from done() in order to specify the __noreturn__ attribute */
1249 winid endwin = WIN_ERR;
1250 boolean bones_ok, have_windows = iflags.window_inited;
1251 struct obj *corpse = (struct obj *) 0;
1257 * The game is now over...
1259 program_state.gameover = 1;
1260 /* in case of a subsequent panic(), there's no point trying to save */
1261 program_state.something_worth_saving = 0;
1262 /* render vision subsystem inoperative */
1263 iflags.vision_inited = 0;
1265 /* might have been killed while using a disposable item, so make sure
1266 it's gone prior to inventory disclosure and creation of bones data */
1268 /* maybe not on object lists; if an active light source, would cause
1269 big trouble (`obj_is_local' panic) for savebones() -> savelev() */
1270 if (thrownobj && thrownobj->where == OBJ_FREE)
1271 dealloc_obj(thrownobj);
1272 if (kickedobj && kickedobj->where == OBJ_FREE)
1273 dealloc_obj(kickedobj);
1275 /* remember time of death here instead of having bones, rip, and
1276 topten figure it out separately and possibly getting different
1277 time or even day if player is slow responding to --More-- */
1278 urealtime.finish_time = endtime = getnow();
1279 urealtime.realtime += (long) (endtime - urealtime.start_timing);
1281 dump_open_log(endtime);
1282 /* Sometimes you die on the first move. Life's not fair.
1283 * On those rare occasions you get hosed immediately, go out
1284 * smiling... :-) -3.
1286 if (moves <= 1 && how < PANICKED) /* You die... --More-- */
1288 pline("Do not pass go. Do not collect 200 %s.", currency(200L));
1290 pline("
\92\8d\88Ó
\88ê
\95b
\81C
\89ö
\89ä
\88ê
\90¶
\81C
\8e\80\96S
\88ê
\95à
\81D");
1293 wait_synch(); /* flush screen output */
1295 (void) signal(SIGINT, (SIG_RET_TYPE) done_intr);
1296 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
1297 (void) signal(SIGQUIT, (SIG_RET_TYPE) done_intr);
1298 sethanguphandler(done_hangup);
1300 #endif /* NO_SIGNAL */
1302 bones_ok = (how < GENOCIDED) && can_make_bones();
1304 if (bones_ok && launch_in_progress())
1305 force_launch_placement();
1307 /* maintain ugrave_arise even for !bones_ok */
1308 if (how == PANICKED)
1309 u.ugrave_arise = (NON_PM - 3); /* no corpse, no grave */
1310 else if (how == BURNING || how == DISSOLVED) /* corpse burns up too */
1311 u.ugrave_arise = (NON_PM - 2); /* leave no corpse */
1312 else if (how == STONING)
1313 u.ugrave_arise = (NON_PM - 1); /* statue instead of corpse */
1314 else if (how == TURNED_SLIME)
1315 u.ugrave_arise = PM_GREEN_SLIME;
1318 killer.format = NO_KILLER_PREFIX;
1321 u.umortality++; /* skipped above when how==QUIT */
1323 Strcpy(killer.name, "quit while already on Charon's boat");
1325 Strcpy(killer.name, "
\8eO
\93r
\82Ì
\90ì
\82Ì
\93n
\82µ
\91D
\82É
\8fæ
\82Á
\82Ä
\82¢
\82é
\8aÔ
\82É
\94²
\82¯
\82½");
1328 if (how == ESCAPED || how == PANICKED)
1329 killer.format = NO_KILLER_PREFIX;
1331 #if 0 /*JP*//*
\93ú
\96{
\8cê
\82Å
\82Í
\8eg
\82í
\82È
\82¢*/
1332 fixup_death(how); /* actually, fixup multi_reason */
1335 if (how != PANICKED) {
1336 /* these affect score and/or bones, but avoid them during panic */
1337 taken = paybill((how == ESCAPED) ? -1 : (how != QUIT));
1341 taken = FALSE; /* lint; assert( !bones_ok ); */
1346 display_nhwindow(WIN_MESSAGE, FALSE);
1348 if (how != PANICKED) {
1352 * This is needed for both inventory disclosure and dumplog.
1353 * Both are optional, so do it once here instead of duplicating
1354 * it in both of those places.
1356 for (obj = invent; obj; obj = obj->nobj) {
1357 makeknown(obj->otyp);
1358 obj->known = obj->bknown = obj->dknown = obj->rknown = 1;
1359 if (Is_container(obj) || obj->otyp == STATUE)
1360 obj->cknown = obj->lknown = 1;
1363 if (strcmp(flags.end_disclose, "none"))
1364 disclose(how, taken);
1366 dump_everything(how, endtime);
1369 /* if pets will contribute to score, populate mydogs list now
1370 (bones creation isn't a factor, but pline() messaging is; used to
1371 be done ever sooner, but we need it to come after dump_everything()
1372 so that any accompanying pets are still on the map during dump) */
1373 if (how == ESCAPED || how == ASCENDED)
1376 /* finish_paybill should be called after disclosure but before bones */
1377 if (bones_ok && taken)
1380 /* grave creation should be after disclosure so it doesn't have
1381 this grave in the current level's features for #overview */
1382 if (bones_ok && u.ugrave_arise == NON_PM
1383 && !(mvitals[u.umonnum].mvflags & G_NOCORPSE)) {
1384 int mnum = u.umonnum;
1387 /* Base corpse on race when not poly'd since original
1388 * u.umonnum is based on role, and all role monsters
1391 mnum = (flags.female && urace.femalenum != NON_PM)
1395 corpse = mk_named_object(CORPSE, &mons[mnum], u.ux, u.uy, plname);
1397 Sprintf(pbuf, "%s, ", plname);
1399 Sprintf(pbuf, "%s
\82Ì
\95æ
\81C", plname);
1400 formatkiller(eos(pbuf), sizeof pbuf - strlen(pbuf), how, TRUE);
1401 make_grave(u.ux, u.uy, pbuf);
1403 pbuf[0] = '\0'; /* clear grave text; also lint suppression */
1405 /* calculate score, before creating bones [container gold] */
1407 int deepest = deepest_lev_reached(FALSE);
1409 umoney = money_cnt(invent);
1411 umoney += hidden_gold(); /* accumulate gold from containers */
1412 tmp = umoney - tmp; /* net gain */
1418 tmp += 50L * (long) (deepest - 1);
1420 tmp += 1000L * (long) ((deepest > 30) ? 10 : deepest - 20);
1421 nowrap_add(u.urexp, tmp);
1423 /* ascension gives a score bonus iff offering to original deity */
1424 if (how == ASCENDED && u.ualign.type == u.ualignbase[A_ORIGINAL]) {
1425 /* retaining original alignment: score *= 2;
1426 converting, then using helm-of-OA to switch back: *= 1.5 */
1427 tmp = (u.ualignbase[A_CURRENT] == u.ualignbase[A_ORIGINAL])
1430 nowrap_add(u.urexp, tmp);
1434 if (u.ugrave_arise >= LOW_PM && u.ugrave_arise != PM_GREEN_SLIME) {
1435 /* give this feedback even if bones aren't going to be created,
1436 so that its presence or absence doesn't tip off the player to
1437 new bones or their lack; it might be a lie if makemon fails */
1439 Your("body rises from the dead as %s...",
1441 Your("
\91Ì
\82Í%s
\82Æ
\82µ
\82Ä
\8e\80\91Ì
\82©
\82ç
\91h
\82Á
\82½
\81D
\81D
\81D",
1442 an(mons[u.ugrave_arise].mname));
1443 display_nhwindow(WIN_MESSAGE, FALSE);
1448 if (!wizard || paranoid_query(ParanoidBones, "Save bones?"))
1450 if (!wizard || paranoid_query(ParanoidBones, "
\8d\9c\82ð
\82¤
\82ß
\82é
\81H"))
1451 savebones(how, endtime, corpse);
1452 /* corpse may be invalid pointer now so
1453 ensure that it isn't used again */
1454 corpse = (struct obj *) 0;
1457 /* update gold for the rip output, which can't use hidden_gold()
1458 (containers will be gone by then if bones just got saved...) */
1459 done_money = umoney;
1461 /* clean up unneeded windows */
1464 free_pickinv_cache(); /* extra persistent window if perm_invent */
1465 if (WIN_INVEN != WIN_ERR) {
1466 destroy_nhwindow(WIN_INVEN), WIN_INVEN = WIN_ERR;
1467 /* precaution in case any late update_inventory() calls occur */
1468 flags.perm_invent = 0;
1470 display_nhwindow(WIN_MESSAGE, TRUE);
1471 destroy_nhwindow(WIN_MAP), WIN_MAP = WIN_ERR;
1472 #ifndef STATUS_HILITES
1473 destroy_nhwindow(WIN_STATUS), WIN_STATUS = WIN_ERR;
1475 destroy_nhwindow(WIN_MESSAGE), WIN_MESSAGE = WIN_ERR;
1477 if (!done_stopprint || flags.tombstone)
1478 endwin = create_nhwindow(NHW_TEXT);
1480 if (how < GENOCIDED && flags.tombstone && endwin != WIN_ERR)
1481 outrip(endwin, how, endtime);
1483 done_stopprint = 1; /* just avoid any more output */
1486 /* 'how' reasons beyond genocide shouldn't show tombstone;
1487 for normal end of game, genocide doesn't either */
1488 if (how <= GENOCIDED) {
1489 dump_redirect(TRUE);
1490 if (iflags.in_dumplog)
1491 genl_outrip(0, how, endtime);
1492 dump_redirect(FALSE);
1495 if (u.uhave.amulet) {
1497 Strcat(killer.name, " (with the Amulet)");
1499 Strcat(killer.name, "
\96\82\8f\9c\82¯
\82ð
\8eè
\82É");
1500 } else if (how == ESCAPED) {
1501 if (Is_astralevel(&u.uz)) /* offered Amulet to wrong deity */
1503 Strcat(killer.name, " (in celestial disgrace)");
1505 Strcat(killer.name, "
\93V
\8fã
\82Å
\92p
\90J
\82ð
\8eó
\82¯
\92E
\8fo
\82µ
\82½");
1506 else if (carrying(FAKE_AMULET_OF_YENDOR))
1508 Strcat(killer.name, " (with a fake Amulet)");
1510 Strcat(killer.name, "
\8bU
\95¨
\82Ì
\96\82\8f\9c\82¯
\82ð
\92Í
\82Ü
\82³
\82ê
\92E
\8fo
\82µ
\82½");
1511 /* don't bother counting to see whether it should be plural */
1515 Sprintf(pbuf, "%s %s the %s...", Goodbye(), plname,
1517 ? (const char *) ((flags.female && urole.name.f)
1520 : (const char *) (flags.female ? "Demigoddess" : "Demigod"));
1522 Sprintf(pbuf, "%s%s
\82Ì%s
\81D
\81D
\81D", Goodbye(),
1524 ? (const char *) ((flags.female && urole.name.f)
1527 : (const char *) (flags.female ? "
\8f\97\90_" : "
\90_"),
1530 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1531 dump_forward_putstr(endwin, 0, "", done_stopprint);
1533 if (how == ESCAPED || how == ASCENDED) {
1536 register struct val_list *val;
1539 for (val = valuables; val->list; val++)
1540 for (i = 0; i < val->size; i++) {
1541 val->list[i].count = 0L;
1543 get_valuables(invent);
1545 /* add points for collected valuables */
1546 for (val = valuables; val->list; val++)
1547 for (i = 0; i < val->size; i++)
1548 if (val->list[i].count != 0L) {
1549 tmp = val->list[i].count
1550 * (long) objects[val->list[i].typ].oc_cost;
1551 nowrap_add(u.urexp, tmp);
1554 /* count the points for artifacts */
1555 artifact_score(invent, TRUE, endwin);
1557 viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */
1560 Strcpy(pbuf, "You");
1562 Strcpy(pbuf, "
\82 \82È
\82½");
1563 if (!Schroedingers_cat) /* check here in case disclosure was off */
1564 Schroedingers_cat = odds_and_ends(invent, CAT_CHECK);
1565 if (Schroedingers_cat) {
1566 int mhp, m_lev = adj_lev(&mons[PM_HOUSECAT]);
1569 nowrap_add(u.urexp, mhp);
1571 Strcat(eos(pbuf), " and Schroedinger's cat");
1573 Strcat(eos(pbuf), "
\82Æ
\83V
\83\85\83\8c\83f
\83B
\83\93\83K
\81[
\82Ì
\94L");
1578 Sprintf(eos(pbuf), " and %s", mon_nam(mtmp));
1580 Sprintf(eos(pbuf), "
\82Æ%s", mon_nam(mtmp));
1582 nowrap_add(u.urexp, mtmp->mhp);
1586 if (!done_stopprint)
1587 Strcat(pbuf, "
\82Í");
1589 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1595 Strcat(pbuf, "
\82Í");
1598 Sprintf(eos(pbuf), "%s with %ld point%s,",
1599 how == ASCENDED ? "went to your reward"
1600 : "escaped from the dungeon",
1601 u.urexp, plur(u.urexp));
1603 Sprintf(eos(pbuf), "%ld
\83|
\83C
\83\93\83g
\83}
\81[
\83N
\82µ%s
\81D",
1605 how==ASCENDED ? "
\8f¸
\93V
\82µ
\82½" : "
\96À
\8b{
\82©
\82ç
\92E
\8fo
\82µ
\82½");
1607 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1609 if (!done_stopprint)
1610 artifact_score(invent, FALSE, endwin); /* list artifacts */
1612 dump_redirect(TRUE);
1613 if (iflags.in_dumplog)
1614 artifact_score(invent, FALSE, 0);
1615 dump_redirect(FALSE);
1618 /* list valuables here */
1619 for (val = valuables; val->list; val++) {
1620 sort_valuables(val->list, val->size);
1621 for (i = 0; i < val->size && !done_stopprint; i++) {
1622 int typ = val->list[i].typ;
1623 long count = val->list[i].count;
1627 if (objects[typ].oc_class != GEM_CLASS || typ <= LAST_GEM) {
1628 otmp = mksobj(typ, FALSE, FALSE);
1629 makeknown(otmp->otyp);
1630 otmp->known = 1; /* for fake amulets */
1631 otmp->dknown = 1; /* seen it (blindness fix) */
1632 if (has_oname(otmp))
1636 Sprintf(pbuf, "%8ld %s (worth %ld %s),", count,
1637 xname(otmp), count * (long) objects[typ].oc_cost,
1640 Sprintf(pbuf, "%ld
\8cÂ
\82Ì%s(%ld%s
\82Ì
\89¿
\92l)
\81C", count,
1641 xname(otmp), count * (long) objects[typ].oc_cost,
1644 obfree(otmp, (struct obj *) 0);
1647 Sprintf(pbuf, "%8ld worthless piece%s of colored glass,",
1648 count, plur(count));
1650 Sprintf(pbuf, "%ld
\8cÂ
\82Ì
\89¿
\92l
\82Ì
\82È
\82¢
\90F
\82Â
\82«
\83K
\83\89\83X
\81C",
1654 dump_forward_putstr(endwin, 0, pbuf, 0);
1659 /* did not escape or ascend */
1660 if (u.uz.dnum == 0 && u.uz.dlevel <= 0) {
1661 /* level teleported out of the dungeon; `how' is DIED,
1662 due to falling or to "arriving at heaven prematurely" */
1664 Sprintf(pbuf, "You %s beyond the confines of the dungeon",
1665 (u.uz.dlevel < 0) ? "passed away" : ends[how]);
1667 Sprintf(pbuf, "
\96À
\8b{
\82Ì
\97Ì
\88æ
\82ð
\89z
\82¦%s
\81D",
1668 (u.uz.dlevel < 0) ? "
\8fÁ
\82¦
\82³
\82Á
\82½" : ends[how]);
1671 /* more conventional demise */
1672 const char *where = dungeons[u.uz.dnum].dname;
1674 if (Is_astralevel(&u.uz))
1676 where = "The Astral Plane";
1678 where = "
\90¸
\97ì
\8aE
\82É
\82Ä";
1680 Sprintf(pbuf, "You %s in %s", ends[how], where);
1682 Sprintf(pbuf, "
\82 \82È
\82½
\82Í%s", where);
1683 if (!In_endgame(&u.uz) && !Is_knox(&u.uz))
1685 Sprintf(eos(pbuf), " on dungeon level %d",
1686 In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz));
1688 Sprintf(eos(pbuf), "
\82Ì
\92n
\89º%d
\8aK
\82Å",
1689 In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz));
1694 Sprintf(eos(pbuf), " with %ld point%s,", u.urexp, plur(u.urexp));
1696 Sprintf(eos(pbuf), " %ld
\83|
\83C
\83\93\83g
\82ð
\83}
\81[
\83N
\82µ
\81C", u.urexp);
1697 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1701 Sprintf(pbuf, "and %ld piece%s of gold, after %ld move%s.", umoney,
1702 plur(umoney), moves, plur(moves));
1704 Sprintf(pbuf, "%ld
\96\87\82Ì
\8bà
\89Ý
\82ð
\8e\9d\82Á
\82Ä
\81C%ld
\95à
\93®
\82¢
\82½
\81D", umoney,
1707 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1710 "You were level %d with a maximum of %d hit point%s when you %s.",
1711 u.ulevel, u.uhpmax, plur(u.uhpmax), ends[how]);
1714 "%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",
1715 ends[how],u.ulevel, u.uhpmax);
1717 dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1718 dump_forward_putstr(endwin, 0, "", done_stopprint);
1719 if (!done_stopprint)
1720 display_nhwindow(endwin, TRUE);
1721 if (endwin != WIN_ERR)
1722 destroy_nhwindow(endwin);
1725 /* "So when I die, the first thing I will see in Heaven is a
1727 if (have_windows && !iflags.toptenwin)
1728 exit_nhwindows((char *) 0), have_windows = FALSE;
1729 topten(how, endtime);
1731 exit_nhwindows((char *) 0);
1733 if (done_stopprint) {
1737 nh_terminate(EXIT_SUCCESS);
1741 container_contents(list, identified, all_containers, reportempty)
1743 boolean identified, all_containers, reportempty;
1745 register struct obj *box, *obj;
1747 boolean cat, deadcat;
1749 for (box = list; box; box = box->nobj) {
1750 if (Is_container(box) || box->otyp == STATUE) {
1751 box->cknown = 1; /* we're looking at the contents now */
1754 cat = deadcat = FALSE;
1755 if (SchroedingersBox(box) && !Schroedingers_cat) {
1756 /* Schroedinger's Cat? */
1757 cat = odds_and_ends(box, CAT_CHECK);
1759 Schroedingers_cat = TRUE;
1764 if (box->otyp == BAG_OF_TRICKS) {
1765 continue; /* wrong type of container */
1766 } else if (box->cobj) {
1767 winid tmpwin = create_nhwindow(NHW_MENU);
1769 sortloot(&box->cobj,
1770 (((flags.sortloot == 'l' || flags.sortloot == 'f')
1771 ? SORTLOOT_LOOT : 0)
1772 | (flags.sortpack ? SORTLOOT_PACK : 0)),
1775 Sprintf(buf, "Contents of %s:", the(xname(box)));
1777 Sprintf(buf, "%s
\82Ì
\92\86\90g
\81F", the(xname(box)));
1778 putstr(tmpwin, 0, buf);
1779 putstr(tmpwin, 0, "");
1780 for (obj = box->cobj; obj; obj = obj->nobj) {
1782 makeknown(obj->otyp);
1783 obj->known = obj->bknown = obj->dknown
1785 if (Is_container(obj) || obj->otyp == STATUE)
1786 obj->cknown = obj->lknown = 1;
1788 putstr(tmpwin, 0, doname(obj));
1792 putstr(tmpwin, 0, "Schroedinger's cat");
1794 putstr(tmpwin, 0, "
\83V
\83\85\83\8c\83f
\83B
\83\93\83K
\81[
\82Ì
\94L");
1797 putstr(tmpwin, 0, "Schroedinger's dead cat");
1799 putstr(tmpwin, 0, "
\83V
\83\85\83\8c\83f
\83B
\83\93\83K
\81[
\82Ì
\94L
\82Ì
\8e\80\91Ì");
1800 display_nhwindow(tmpwin, TRUE);
1801 destroy_nhwindow(tmpwin);
1803 container_contents(box->cobj, identified, TRUE,
1805 } else if (cat || deadcat) {
1807 pline("%s Schroedinger's %scat!", Tobjnam(box, "contain"),
1808 deadcat ? "dead " : "");
1810 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),
1811 deadcat ? "
\82Ì
\8e\80\91Ì" : "");
1813 display_nhwindow(WIN_MESSAGE, FALSE);
1814 } else if (reportempty) {
1816 pline("%s is empty.", upstart(thesimpleoname(box)));
1818 pline("%s
\82Í
\8bó
\82Á
\82Û
\82¾
\81D", xname(box));
1819 display_nhwindow(WIN_MESSAGE, FALSE);
1822 if (!all_containers)
1827 /* should be called with either EXIT_SUCCESS or EXIT_FAILURE */
1829 nh_terminate(status)
1832 program_state.in_moveloop = 0; /* won't be returning to normal play */
1834 getreturn("to exit");
1836 /* don't bother to try to release memory if we're in panic mode, to
1837 avoid trouble in case that happens to be due to memory problems */
1838 if (!program_state.panicking) {
1845 * This is liable to draw a warning if compiled with gcc, but it's
1846 * more important to flag panic() -> really_done() -> nh_terminate()
1847 * as __noreturn__ then to avoid the warning.
1849 /* don't call exit() if already executing within an exit handler;
1850 that would cancel any other pending user-mode handlers */
1851 if (program_state.exiting)
1854 program_state.exiting = 1;
1856 jputchar('\0'); /* reset terminal */
1858 nethack_exit(status);
1861 extern const int monstr[];
1863 enum vanq_order_modes {
1873 NUM_VANQ_ORDER_MODES
1876 static const char *vanqorders[NUM_VANQ_ORDER_MODES] = {
1877 "traditional: by monster level, by internal monster index",
1878 "by monster toughness, by internal monster index",
1879 "alphabetically, first unique monsters, then others",
1880 "alphabetically, unique monsters and others intermixed",
1881 "by monster class, high to low level within class",
1882 "by monster class, low to high level within class",
1883 "by count, high to low, by internal index within tied count",
1884 "by count, low to high, by internal index within tied count",
1886 static int vanq_sortmode = VANQ_MLVL_MNDX;
1888 STATIC_PTR int CFDECLSPEC
1889 vanqsort_cmp(vptr1, vptr2)
1890 const genericptr vptr1;
1891 const genericptr vptr2;
1893 int indx1 = *(short *) vptr1, indx2 = *(short *) vptr2,
1894 mlev1, mlev2, mstr1, mstr2, uniq1, uniq2, died1, died2, res;
1895 const char *name1, *name2, *punct;
1898 switch (vanq_sortmode) {
1900 case VANQ_MLVL_MNDX:
1901 /* sort by monster level */
1902 mlev1 = mons[indx1].mlevel, mlev2 = mons[indx2].mlevel;
1903 res = mlev2 - mlev1; /* mlevel high to low */
1905 case VANQ_MSTR_MNDX:
1906 /* sort by monster toughness */
1907 mstr1 = monstr[indx1], mstr2 = monstr[indx2];
1908 res = mstr2 - mstr1; /* monstr high to low */
1910 case VANQ_ALPHA_SEP:
1911 uniq1 = ((mons[indx1].geno & G_UNIQ) && indx1 != PM_HIGH_PRIEST);
1912 uniq2 = ((mons[indx2].geno & G_UNIQ) && indx2 != PM_HIGH_PRIEST);
1913 if (uniq1 ^ uniq2) { /* one or other uniq, but not both */
1914 res = uniq2 - uniq1;
1916 } /* else both unique or neither unique */
1918 case VANQ_ALPHA_MIX:
1919 name1 = mons[indx1].mname, name2 = mons[indx2].mname;
1920 res = strcmpi(name1, name2); /* caseblind alhpa, low to high */
1922 case VANQ_MCLS_HTOL:
1923 case VANQ_MCLS_LTOH:
1924 /* mons[].mlet is a small integer, 1..N, of type plain char;
1925 if 'char' happens to be unsigned, (mlet1 - mlet2) would yield
1926 an inappropriate result when mlet2 is greater than mlet1,
1927 so force our copies (mcls1, mcls2) to be signed */
1928 mcls1 = (schar) mons[indx1].mlet, mcls2 = (schar) mons[indx2].mlet;
1929 /* S_ANT through S_ZRUTY correspond to lowercase monster classes,
1930 S_ANGEL through S_ZOMBIE correspond to uppercase, and various
1931 punctuation characters are used for classes beyond those */
1932 if (mcls1 > S_ZOMBIE && mcls2 > S_ZOMBIE) {
1933 /* force a specific order to the punctuation classes that's
1934 different from the internal order;
1935 internal order is ok if neither or just one is punctuation
1936 since letters have lower values so come out before punct */
1937 static const char punctclasses[] = {
1938 S_LIZARD, S_EEL, S_GOLEM, S_GHOST, S_DEMON, S_HUMAN, '\0'
1941 if ((punct = index(punctclasses, mcls1)) != 0)
1942 mcls1 = (schar) (S_ZOMBIE + 1 + (int) (punct - punctclasses));
1943 if ((punct = index(punctclasses, mcls2)) != 0)
1944 mcls2 = (schar) (S_ZOMBIE + 1 + (int) (punct - punctclasses));
1946 res = mcls1 - mcls2; /* class */
1948 mlev1 = mons[indx1].mlevel, mlev2 = mons[indx2].mlevel;
1949 res = mlev1 - mlev2; /* mlevel low to high */
1950 if (vanq_sortmode == VANQ_MCLS_HTOL)
1951 res = -res; /* mlevel high to low */
1954 case VANQ_COUNT_H_L:
1955 case VANQ_COUNT_L_H:
1956 died1 = mvitals[indx1].died, died2 = mvitals[indx2].died;
1957 res = died2 - died1; /* dead count high to low */
1958 if (vanq_sortmode == VANQ_COUNT_L_H)
1959 res = -res; /* dead count low to high */
1962 /* tiebreaker: internal mons[] index */
1964 res = indx1 - indx2; /* mndx low to high */
1968 /* returns -1 if cancelled via ESC */
1973 menu_item *selected;
1977 tmpwin = create_nhwindow(NHW_MENU);
1979 any = zeroany; /* zero out all bits */
1980 for (i = 0; i < SIZE(vanqorders); i++) {
1981 if (i == VANQ_ALPHA_MIX || i == VANQ_MCLS_HTOL) /* skip these */
1984 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, vanqorders[i],
1985 (i == vanq_sortmode) ? MENU_SELECTED : MENU_UNSELECTED);
1988 end_menu(tmpwin, "Sort order for vanquished monster counts");
1990 end_menu(tmpwin, "
\93|
\82µ
\82½
\93G
\82Ì
\83\
\81[
\83g
\8f\87");
1992 n = select_menu(tmpwin, PICK_ONE, &selected);
1993 destroy_nhwindow(tmpwin);
1995 choice = selected[0].item.a_int - 1;
1996 /* skip preselected entry if we have more than one item chosen */
1997 if (n > 1 && choice == vanq_sortmode)
1998 choice = selected[1].item.a_int - 1;
1999 free((genericptr_t) selected);
2000 vanq_sortmode = choice;
2002 return (n < 0) ? -1 : vanq_sortmode;
2005 /* #vanquished command */
2009 list_vanquished('a', FALSE);
2013 /* high priests aren't unique but are flagged as such to simplify something */
2014 #define UniqCritterIndx(mndx) ((mons[mndx].geno & G_UNIQ) \
2015 && mndx != PM_HIGH_PRIEST)
2018 list_vanquished(defquery, ask)
2024 unsigned ntypes, ni;
2025 long total_killed = 0L;
2027 short mindx[NUMMONS];
2028 char c, buf[BUFSZ], buftoo[BUFSZ];
2029 boolean dumping; /* for DUMPLOG; doesn't need to be conditional */
2031 dumping = (defquery == 'd');
2035 /* get totals first */
2037 for (i = LOW_PM; i < NUMMONS; i++) {
2038 if ((nkilled = (int) mvitals[i].died) == 0)
2040 mindx[ntypes++] = i;
2041 total_killed += (long) nkilled;
2044 /* vanquished creatures list;
2045 * includes all dead monsters, not just those killed by the player
2048 char mlet, prev_mlet = 0; /* used as small integer, not character */
2049 boolean class_header, uniq_header, was_uniq = FALSE;
2052 c = ask ? yn_function(
2053 "Do you want an account of creatures vanquished?",
2054 ynaqchars, defquery)
2057 c = ask ? yn_function(
2058 "
\93|
\82µ
\82½
\93G
\82Ì
\88ê
\97\97\82ð
\8c©
\82Ü
\82·
\82©
\81H",
2064 if (c == 'y' || c == 'a') {
2065 if (c == 'a') { /* ask player to choose sort order */
2066 /* choose value for vanq_sortmode via menu; ESC cancels list
2067 of vanquished monsters but does not set 'done_stopprint' */
2068 if (set_vanq_order() < 0)
2071 uniq_header = (vanq_sortmode == VANQ_ALPHA_SEP);
2072 class_header = (vanq_sortmode == VANQ_MCLS_LTOH
2073 || vanq_sortmode == VANQ_MCLS_HTOL);
2075 klwin = create_nhwindow(NHW_MENU);
2077 putstr(klwin, 0, "Vanquished creatures:");
2079 putstr(klwin, 0, "
\93|
\82µ
\82½
\93G
\81F");
2081 putstr(klwin, 0, "");
2083 qsort((genericptr_t) mindx, ntypes, sizeof *mindx, vanqsort_cmp);
2084 for (ni = 0; ni < ntypes; ni++) {
2086 nkilled = mvitals[i].died;
2087 mlet = mons[i].mlet;
2088 if (class_header && mlet != prev_mlet) {
2089 Strcpy(buf, def_monsyms[(int) mlet].explain);
2090 putstr(klwin, ask ? 0 : iflags.menu_headings,
2094 if (UniqCritterIndx(i)) {
2096 Sprintf(buf, "%s%s",
2097 !type_is_pname(&mons[i]) ? "the " : "",
2100 Sprintf(buf, "%s", mons[i].mname);
2106 Sprintf(eos(buf), " (twice)");
2109 Sprintf(eos(buf), " (thrice)");
2112 Sprintf(eos(buf), " (%d times)", nkilled);
2116 Sprintf(eos(buf)," (%d
\89ñ)", nkilled);
2121 if (uniq_header && was_uniq) {
2122 putstr(klwin, 0, "");
2125 /* trolls or undead might have come back,
2126 but we don't keep track of that */
2128 Strcpy(buf, an(mons[i].mname));
2131 Sprintf(buf, "%3d %s", nkilled,
2132 makeplural(mons[i].mname));
2134 Sprintf(buf, "%d
\91Ì
\82Ì%s", nkilled,
2138 /* number of leading spaces to match 3 digit prefix */
2140 pfx = !strncmpi(buf, "the ", 3) ? 0
2141 : !strncmpi(buf, "an ", 3) ? 1
2142 : !strncmpi(buf, "a ", 2) ? 2
2143 : !digit(buf[2]) ? 4 : 0;
2145 pfx = !digit(buf[2]) ? 4 : 0;
2149 Sprintf(buftoo, "%*s%s", pfx, "", buf);
2150 putstr(klwin, 0, buftoo);
2153 * if (Hallucination)
2154 * putstr(klwin, 0, "and a partridge in a pear tree");
2158 putstr(klwin, 0, "");
2160 Sprintf(buf, "%ld creatures vanquished.", total_killed);
2162 Sprintf(buf, "%ld
\95C
\82Ì
\93G
\82ð
\93|
\82µ
\82½
\81D", total_killed);
2163 putstr(klwin, 0, buf);
2165 display_nhwindow(klwin, TRUE);
2166 destroy_nhwindow(klwin);
2168 } else if (defquery == 'a') {
2169 /* #dovanquished rather than final disclosure, so pline() is ok */
2171 pline("No creatures have been vanquished.");
2173 pline("
\93|
\82µ
\82½
\93G
\82Í
\82¢
\82È
\82©
\82Á
\82½
\81D");
2175 } else if (dumping) {
2176 putstr(0, 0, "No creatures were vanquished."); /* not pline() */
2181 /* number of monster species which have been genocided */
2187 for (i = LOW_PM; i < NUMMONS; ++i) {
2188 if (mvitals[i].mvflags & G_GENOD) {
2190 if (UniqCritterIndx(i))
2191 impossible("unique creature '%d: %s' genocided?",
2203 for (i = LOW_PM; i < NUMMONS; ++i) {
2204 if (UniqCritterIndx(i))
2206 if ((mvitals[i].mvflags & G_GONE) == G_EXTINCT)
2213 list_genocided(defquery, ask)
2218 int ngenocided, nextinct;
2222 boolean dumping; /* for DUMPLOG; doesn't need to be conditional */
2224 dumping = (defquery == 'd');
2228 ngenocided = num_genocides();
2229 nextinct = num_extinct();
2231 /* genocided or extinct species list */
2232 if (ngenocided != 0 || nextinct != 0) {
2234 Sprintf(buf, "Do you want a list of %sspecies%s%s?",
2235 (nextinct && !ngenocided) ? "extinct " : "",
2236 (ngenocided) ? " genocided" : "",
2237 (nextinct && ngenocided) ? " and extinct" : "");
2239 Sprintf(buf, "%s%s%s
\82µ
\82½
\8eí
\82Ì
\88ê
\97\97\82ð
\8c©
\82Ü
\82·
\82©
\81H",
2240 (nextinct && !ngenocided) ? "
\90â
\96Å" : "",
2241 (ngenocided) ? "
\8bs
\8eE" : "",
2242 (nextinct && ngenocided) ? "
\82¨
\82æ
\82Ñ
\90â
\96Å" : "");
2244 c = ask ? yn_function(buf, ynqchars, defquery) : defquery;
2248 klwin = create_nhwindow(NHW_MENU);
2250 Sprintf(buf, "%s%s species:",
2251 (ngenocided) ? "Genocided" : "Extinct",
2252 (nextinct && ngenocided) ? " or extinct" : "");
2254 Sprintf(buf, "%s%s
\82µ
\82½
\8eí:",
2255 (ngenocided) ? "
\8bs
\8eE" : "
\90â
\96Å",
2256 (nextinct && ngenocided) ? "
\82Ü
\82½
\82Í
\90â
\96Å" : "");
2258 putstr(klwin, 0, buf);
2260 putstr(klwin, 0, "");
2262 for (i = LOW_PM; i < NUMMONS; i++) {
2263 /* uniques can't be genocided but can become extinct;
2264 however, they're never reported as extinct, so skip them */
2265 if (UniqCritterIndx(i))
2267 if (mvitals[i].mvflags & G_GONE) {
2268 Sprintf(buf, " %s", makeplural(mons[i].mname));
2270 * "Extinct" is unfortunate terminology. A species
2271 * is marked extinct when its birth limit is reached,
2272 * but there might be members of the species still
2273 * alive, contradicting the meaning of the word.
2275 if ((mvitals[i].mvflags & G_GONE) == G_EXTINCT)
2277 Strcat(buf, " (extinct)");
2279 Strcat(buf, "(
\90â
\96Å)");
2280 putstr(klwin, 0, buf);
2284 putstr(klwin, 0, "");
2285 if (ngenocided > 0) {
2287 Sprintf(buf, "%d species genocided.", ngenocided);
2289 Sprintf(buf, "%d
\8eí
\97Þ
\82Ì
\8eí
\82ð
\8bs
\8eE
\82µ
\82½
\81D", ngenocided);
2290 putstr(klwin, 0, buf);
2294 Sprintf(buf, "%d species extinct.", nextinct);
2296 Sprintf(buf, "%d
\8eí
\97Þ
\82Ì
\8eí
\82ð
\90â
\96Å
\82³
\82¹
\82½
\81D", nextinct);
2297 putstr(klwin, 0, buf);
2300 display_nhwindow(klwin, TRUE);
2301 destroy_nhwindow(klwin);
2304 } else if (dumping) {
2305 putstr(0, 0, "No species were genocided or became extinct.");
2310 /* set a delayed killer, ensure non-delayed killer is cleared out */
2312 delayed_killer(id, format, killername)
2315 const char *killername;
2317 struct kinfo *k = find_delayed_killer(id);
2319 if (k == (struct kinfo *) 0) {
2320 /* no match, add a new delayed killer to the list */
2321 k = (struct kinfo *) alloc(sizeof(struct kinfo));
2322 (void) memset((genericptr_t)k, 0, sizeof(struct kinfo));
2324 k->next = killer.next;
2329 Strcpy(k->name, killername ? killername : "");
2334 find_delayed_killer(id)
2339 for (k = killer.next; k != (struct kinfo *) 0; k = k->next) {
2347 dealloc_killer(kptr)
2350 struct kinfo *prev = &killer, *k;
2352 if (kptr == (struct kinfo *) 0)
2354 for (k = killer.next; k != (struct kinfo *) 0; k = k->next) {
2360 if (k == (struct kinfo *) 0) {
2361 impossible("dealloc_killer not on list");
2363 prev->next = k->next;
2364 free((genericptr_t) k);
2369 save_killers(fd, mode)
2375 if (perform_bwrite(mode)) {
2376 for (kptr = &killer; kptr != (struct kinfo *) 0; kptr = kptr->next) {
2377 bwrite(fd, (genericptr_t) kptr, sizeof(struct kinfo));
2380 if (release_data(mode)) {
2381 while (killer.next) {
2382 kptr = killer.next->next;
2383 free((genericptr_t) killer.next);
2395 for (kptr = &killer; kptr != (struct kinfo *) 0; kptr = kptr->next) {
2396 mread(fd, (genericptr_t) kptr, sizeof(struct kinfo));
2398 kptr->next = (struct kinfo *) alloc(sizeof(struct kinfo));
2410 while (*p && isspace((uchar) *p))
2414 while (*p && !isspace((uchar) *p))
2426 out += strlen(out); /* eos() */
2427 while (*in && isspace((uchar) *in))
2429 while (*in && !isspace((uchar) *in))
2435 /*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*/
2437 build_english_list(in)
2441 int len = (int) strlen(p), words = wordcount(p);
2443 /* +3: " or " - " "; +(words - 1): (N-1)*(", " - " ") */
2445 len += 3 + (words - 1);
2446 out = (char *) alloc(len + 1);
2447 *out = '\0'; /* bel_copy1() appends */
2451 impossible("no words in list");
2459 /* "first or second" */
2463 /* "first, second, or third */
2467 } while (--words > 1);