OSDN Git Service

upgrade to 3.6.1
[jnethack/source.git] / src / end.c
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. */
5
6 #define NEED_VARARGS /* comment line for pre-compiled headers */
7
8 #include "hack.h"
9 #include "lev.h"
10 #ifndef NO_SIGNAL
11 #include <signal.h>
12 #endif
13 #include <ctype.h>
14 #include <limits.h>
15 #include "dlb.h"
16
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)))
19
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
24
25 struct valuable_data {
26     long count;
27     int typ;
28 };
29
30 static struct valuable_data
31     gems[LAST_GEM + 1 - FIRST_GEM + 1], /* 1 extra for glass */
32     amulets[LAST_AMULET + 1 - FIRST_AMULET];
33
34 static struct val_list {
35     struct valuable_data *list;
36     int size;
37 } valuables[] = { { gems, sizeof gems / sizeof *gems },
38                   { amulets, sizeof amulets / sizeof *amulets },
39                   { 0, 0 } };
40
41 #ifndef NO_SIGNAL
42 STATIC_PTR void FDECL(done_intr, (int));
43 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
44 static void FDECL(done_hangup, (int));
45 #endif
46 #endif
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,
55                                                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 *));
60 #ifdef DUMPLOG
61 STATIC_DCL void NDECL(dump_plines);
62 #endif
63 STATIC_DCL void FDECL(dump_everything, (int, time_t));
64 STATIC_DCL int NDECL(num_extinct);
65
66 #if defined(__BEOS__) || defined(MICRO) || defined(WIN32) || defined(OS2)
67 extern void FDECL(nethack_exit, (int));
68 #else
69 #define nethack_exit exit
70 #endif
71
72 #define done_stopprint program_state.stopprint
73
74 #ifndef PANICTRACE
75 #define NH_abort NH_abort_
76 #endif
77
78 #ifdef AMIGA
79 #define NH_abort_() Abort(0)
80 #else
81 #ifdef SYSV
82 #define NH_abort_() (void) abort()
83 #else
84 #ifdef WIN32
85 #define NH_abort_() win32_abort()
86 #else
87 #define NH_abort_() abort()
88 #endif
89 #endif /* !SYSV */
90 #endif /* !AMIGA */
91
92 #ifdef PANICTRACE
93 #include <errno.h>
94 #ifdef PANICTRACE_LIBC
95 #include <execinfo.h>
96 #endif
97
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
105  */
106 #ifdef SYSCF
107 #define SYSOPT_PANICTRACE_GDB sysopt.panictrace_gdb
108 #ifdef PANICTRACE_LIBC
109 #define SYSOPT_PANICTRACE_LIBC sysopt.panictrace_libc
110 #else
111 #define SYSOPT_PANICTRACE_LIBC 0
112 #endif
113 #else
114 #define SYSOPT_PANICTRACE_GDB (nh_getenv("NETHACK_USE_GDB") == 0 ? 0 : 2)
115 #ifdef PANICTRACE_LIBC
116 #define SYSOPT_PANICTRACE_LIBC 1
117 #else
118 #define SYSOPT_PANICTRACE_LIBC 0
119 #endif
120 #endif
121
122 static void NDECL(NH_abort);
123 #ifndef NO_SIGNAL
124 static void FDECL(panictrace_handler, (int));
125 #endif
126 static boolean NDECL(NH_panictrace_libc);
127 static boolean NDECL(NH_panictrace_gdb);
128
129 #ifndef NO_SIGNAL
130 /*ARGSUSED*/
131 void panictrace_handler(
132     sig_unused) /* called as signal() handler, so sent at least one arg */
133 int sig_unused UNUSED;
134 {
135 #define SIG_MSG "\nSignal received.\n"
136     (void) write(2, SIG_MSG, sizeof(SIG_MSG) - 1);
137     NH_abort();
138 }
139
140 void
141 panictrace_setsignals(set)
142 boolean set;
143 {
144 #define SETSIGNAL(sig) \
145     (void) signal(sig, set ? (SIG_RET_TYPE) panictrace_handler : SIG_DFL);
146 #ifdef SIGILL
147     SETSIGNAL(SIGILL);
148 #endif
149 #ifdef SIGTRAP
150     SETSIGNAL(SIGTRAP);
151 #endif
152 #ifdef SIGIOT
153     SETSIGNAL(SIGIOT);
154 #endif
155 #ifdef SIGBUS
156     SETSIGNAL(SIGBUS);
157 #endif
158 #ifdef SIGFPE
159     SETSIGNAL(SIGFPE);
160 #endif
161 #ifdef SIGSEGV
162     SETSIGNAL(SIGSEGV);
163 #endif
164 #ifdef SIGSTKFLT
165     SETSIGNAL(SIGSTKFLT);
166 #endif
167 #ifdef SIGSYS
168     SETSIGNAL(SIGSYS);
169 #endif
170 #ifdef SIGEMT
171     SETSIGNAL(SIGEMT);
172 #endif
173 #undef SETSIGNAL
174 }
175 #endif /* NO_SIGNAL */
176
177 static void
178 NH_abort()
179 {
180     int gdb_prio = SYSOPT_PANICTRACE_GDB;
181     int libc_prio = SYSOPT_PANICTRACE_LIBC;
182     static boolean aborting = FALSE;
183
184     if (aborting)
185         return;
186     aborting = TRUE;
187
188 #ifndef VMS
189     if (gdb_prio == libc_prio && gdb_prio > 0)
190         gdb_prio++;
191
192     if (gdb_prio > libc_prio) {
193         (void) (NH_panictrace_gdb() || (libc_prio && NH_panictrace_libc()));
194     } else {
195         (void) (NH_panictrace_libc() || (gdb_prio && NH_panictrace_gdb()));
196     }
197
198 #else /* VMS */
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 */
204
205 #endif /* ?VMS */
206
207 #ifndef NO_SIGNAL
208     panictrace_setsignals(FALSE);
209 #endif
210     NH_abort_();
211 }
212
213 static boolean
214 NH_panictrace_libc()
215 {
216 #ifdef PANICTRACE_LIBC
217     void *bt[20];
218     size_t count, x;
219     char **info;
220
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]);
226     }
227     /* free(info);   -- Don't risk it. */
228     return TRUE;
229 #else
230     return FALSE;
231 #endif /* !PANICTRACE_LIBC */
232 }
233
234 /*
235  *   fooPATH  file system path for foo
236  *   fooVAR   (possibly const) variable containing fooPATH
237  */
238 #ifdef PANICTRACE_GDB
239 #ifdef SYSCF
240 #define GDBVAR sysopt.gdbpath
241 #define GREPVAR sysopt.greppath
242 #else /* SYSCF */
243 #define GDBVAR GDBPATH
244 #define GREPVAR GREPPATH
245 #endif /* SYSCF */
246 #endif /* PANICTRACE_GDB */
247
248 static boolean
249 NH_panictrace_gdb()
250 {
251 #ifdef PANICTRACE_GDB
252     /* A (more) generic method to get a stack trace - invoke
253      * gdb on ourself. */
254     char *gdbpath = GDBVAR;
255     char *greppath = GREPVAR;
256     char buf[BUFSZ];
257     FILE *gdb;
258
259     if (gdbpath == NULL || gdbpath[0] == 0)
260         return FALSE;
261     if (greppath == NULL || greppath[0] == 0)
262         return FALSE;
263
264     sprintf(buf, "%s -n -q %s %d 2>&1 | %s '^#'", gdbpath, ARGV0, getpid(),
265             greppath);
266     gdb = popen(buf, "w");
267     if (gdb) {
268         raw_print("Generating more information you may report:\n");
269         fprintf(gdb, "bt\nquit\ny");
270         fflush(gdb);
271         sleep(4); /* ugly */
272         pclose(gdb);
273         return TRUE;
274     } else {
275         return FALSE;
276     }
277 #else
278     return FALSE;
279 #endif /* !PANICTRACE_GDB */
280 }
281 #endif /* PANICTRACE */
282
283 #if 0 /*JP*//*\93ú\96{\8cê\82Å\82Í\8eg\82í\82È\82¢*/
284 /*
285  * The order of these needs to match the macros in hack.h.
286  */
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"
293 };
294 #endif /*JP*/
295
296 static NEARDATA const char *ends[] = {
297     /* "when you %s" */
298 #if 0 /*JP*/
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½"
314 #endif
315 };
316
317 static boolean Schroedingers_cat = FALSE;
318
319 /*ARGSUSED*/
320 void
321 done1(sig_unused) /* called as signal() handler, so sent at least one arg */
322 int sig_unused UNUSED;
323 {
324 #ifndef NO_SIGNAL
325     (void) signal(SIGINT, SIG_IGN);
326 #endif
327     if (flags.ignintr) {
328 #ifndef NO_SIGNAL
329         (void) signal(SIGINT, (SIG_RET_TYPE) done1);
330 #endif
331         clear_nhwindow(WIN_MESSAGE);
332         curs_on_u();
333         wait_synch();
334         if (multi > 0)
335             nomul(0);
336     } else {
337         (void) done2();
338     }
339 }
340
341 /* "#quit" command or keyboard interrupt */
342 int
343 done2()
344 {
345 /*JP
346     if (!paranoid_query(ParanoidQuit, "Really quit?")) {
347 */
348     if (!paranoid_query(ParanoidQuit, "\96{\93\96\82É\82â\82ß\82é\81H")) {
349 #ifndef NO_SIGNAL
350         (void) signal(SIGINT, (SIG_RET_TYPE) done1);
351 #endif
352         clear_nhwindow(WIN_MESSAGE);
353         curs_on_u();
354         wait_synch();
355         if (multi > 0)
356             nomul(0);
357         if (multi == 0) {
358             u.uinvulnerable = FALSE; /* avoid ctrl-C bug -dlc */
359             u.usleep = 0;
360         }
361         return 0;
362     }
363 #if (defined(UNIX) || defined(VMS) || defined(LATTICE))
364     if (wizard) {
365         int c;
366 #ifdef VMS
367         extern int debuggable; /* sys/vms/vmsmisc.c, vmsunix.c */
368
369         c = !debuggable ? 'n' : ynq("Enter debugger?");
370 #else
371 #ifdef LATTICE
372         c = ynq("Create SnapShot?");
373 #else
374         c = ynq("Dump core?");
375 #endif
376 #endif
377         if (c == 'y') {
378 #ifndef NO_SIGNAL
379             (void) signal(SIGINT, (SIG_RET_TYPE) done1);
380 #endif
381             exit_nhwindows((char *) 0);
382             NH_abort();
383         } else if (c == 'q')
384             done_stopprint++;
385     }
386 #endif
387 #ifndef LINT
388     done(QUIT);
389 #endif
390     return 0;
391 }
392
393 #ifndef NO_SIGNAL
394 /*ARGSUSED*/
395 STATIC_PTR void
396 done_intr(sig_unused) /* called as signal() handler, so sent at least 1 arg */
397 int sig_unused UNUSED;
398 {
399     done_stopprint++;
400     (void) signal(SIGINT, SIG_IGN);
401 #if defined(UNIX) || defined(VMS)
402     (void) signal(SIGQUIT, SIG_IGN);
403 #endif
404     return;
405 }
406
407 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
408 /* signal() handler */
409 static void
410 done_hangup(sig)
411 int sig;
412 {
413     program_state.done_hup++;
414     sethanguphandler((void FDECL((*), (int) )) SIG_IGN);
415     done_intr(sig);
416     return;
417 }
418 #endif
419 #endif /* NO_SIGNAL */
420
421 void
422 done_in_by(mtmp, how)
423 struct monst *mtmp;
424 int how;
425 {
426     char buf[BUFSZ];
427     struct permonst *mptr = mtmp->data,
428                     *champtr = ((mtmp->cham >= LOW_PM)
429                                    ? &mons[mtmp->cham]
430                                    : mptr);
431     boolean distorted = (boolean) (Hallucination && canspotmon(mtmp)),
432             mimicker = (mtmp->m_ap_type == M_AP_MONSTER),
433             imitator = (mptr != champtr || mimicker);
434
435 /*JP
436     You((how == STONING) ? "turn to stone..." : "die...");
437 */
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 */
440     buf[0] = '\0';
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))
448             Strcat(buf, "the ");
449         killer.format = KILLED_BY;
450     }
451     /* _the_ <invisible> <distorted> ghost of Dudley */
452     if (mptr == &mons[PM_GHOST] && has_mname(mtmp)) {
453         Strcat(buf, "the ");
454         killer.format = KILLED_BY;
455     }
456 #endif
457     if (mtmp->minvis)
458 /*JP
459         Strcat(buf, "invisible ");
460 */
461         Strcat(buf, "\93§\96¾\82È");
462     if (distorted)
463 /*JP
464         Strcat(buf, "hallucinogen-distorted ");
465 */
466         Strcat(buf, "\8c\8ao\82Å\98c\82ñ\82¾");
467
468     if (imitator) {
469         char shape[BUFSZ];
470         const char *realnm = champtr->mname, *fakenm = mptr->mname;
471         boolean alt = is_vampshifter(mtmp);
472
473         if (mimicker) {
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;
478 #if 0 /*JP*/
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" */
483             fakenm = "bat";
484 #else
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è";
490 #endif
491         }
492 #if 0 /*JP*/
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);
500         else /* "a"/"an" */
501             Strcpy(shape, an(fakenm));
502 #else /*JP:\93ú\96{\8cê\82Å\82Í\83V\83\93\83v\83\8b*/
503         Strcpy(shape, fakenm);
504 #endif
505         /* omit "called" to avoid excessive verbosity */
506 #if 0 /*JP*/
507         Sprintf(eos(buf),
508                 alt ? "%s in %s form"
509                     : mimicker ? "%s disguised as %s"
510                                : "%s imitating %s",
511                 realnm, shape);
512 #else
513         Sprintf(eos(buf),
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",
517                 shape, realnm);
518 #endif
519         mptr = mtmp->data; /* reset for mimicker case */
520     } else if (mptr == &mons[PM_GHOST]) {
521 #if 0 /*JP*/
522         Strcat(buf, "ghost");
523         if (has_mname(mtmp))
524             Sprintf(eos(buf), " of %s", MNAME(mtmp));
525 #else
526         if (has_mname(mtmp))
527             Sprintf(eos(buf), "%s\82Ì\97H\97ì", MNAME(mtmp));
528         else
529             Strcat(buf, "\97H\97ì");
530 #endif
531     } else if (mtmp->isshk) {
532 #if 0 /*JP*/
533         const char *shknm = shkname(mtmp),
534                    *honorific = shkname_is_pname(mtmp) ? ""
535                                    : mtmp->female ? "Ms. " : "Mr. ";
536
537         Sprintf(eos(buf), "%s%s, the shopkeeper", honorific, shknm);
538 #else
539         Sprintf(eos(buf), "%s\82Æ\82¢\82¤\96¼\82Ì\93X\8eå", shkname(mtmp));
540 #endif
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));
546     } else {
547 #if 0 /*JP*/
548         Strcat(buf, mptr->mname);
549         if (has_mname(mtmp))
550             Sprintf(eos(buf), " called %s", MNAME(mtmp));
551 #else
552         Strcat(buf, mptr->mname);
553 #endif
554     }
555
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;
570
571 #if 1 /*JP*/
572     if (how == STONING){
573         /*JP
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
576          */
577         Strcat(buf, "\82Ì\8dU\8c\82\82Å");
578     }
579     if (how == DIED){
580         /*JP
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
583          */
584         killer.format = KILLED_SUFFIX;
585         done(DIED);
586     }
587 #endif
588     done(how);
589     return;
590 }
591
592 /* some special cases for overriding while-helpless reason */
593 static const struct {
594     int why, unmulti;
595     const char *exclude, *include;
596 } death_fixups[] = {
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" },
605 };
606
607 /* clear away while-helpless when the cause of death caused that
608    helplessness (ie, "petrified by <foo> while getting stoned") */
609 STATIC_DCL void
610 fixup_death(how)
611 int how;
612 {
613     int i;
614
615     if (multi_reason) {
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 */
624                     multi = 0L;
625                 break;
626             }
627     }
628 }
629
630 #if defined(WIN32) && !defined(SYSCF)
631 #define NOTIFY_NETHACK_BUGS
632 #endif
633
634 /*VARARGS1*/
635 void panic
636 VA_DECL(const char *, str)
637 {
638     VA_START(str);
639     VA_INIT(str, char *);
640
641     if (program_state.panicking++)
642         NH_abort(); /* avoid loops - this should never happen*/
643
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 */
649     }
650
651     raw_print(program_state.gameover
652 /*JP
653                   ? "Postgame wrapup disrupted."
654 */
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
657 /*JP
658                         ? "Program initialization has failed."
659 */
660                         ? "\83v\83\8d\83O\83\89\83\80\82Ì\8f\89\8aú\89»\82É\8e¸\94s\82µ\82½\81D"
661 /*JP
662                         : "Suddenly, the dungeon collapses.");
663 */
664                         : "\93Ë\91R\96À\8b{\82ª\95ö\82ê\82½\81D");
665 #ifndef MICRO
666 #if defined(NOTIFY_NETHACK_BUGS)
667     if (!wizard)
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");
672 #else
673     if (!wizard) {
674 #if 0 /*JP*/
675         const char *maybe_rebuild = !program_state.something_worth_saving
676                                      ? "."
677                                      : "\nand it may be possible to rebuild.";
678 #else
679         const char *maybe_rebuild = !program_state.something_worth_saving
680                                      ? "\81D"
681                                      : "\n\95\9c\8b\8c\82Å\82«\82é\89Â\94\\90«\82ª\82 \82è\82Ü\82·\81D";
682 #endif
683
684         if (sysopt.support)
685             raw_printf("To report this error, %s%s", sysopt.support,
686                        maybe_rebuild);
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);
690         else
691 #if 0 /*JP*/
692             raw_printf("Report error to \"%s\"%s", WIZARD_NAME,
693                        maybe_rebuild);
694 #else
695             raw_printf("\"%s\"\82É\83G\83\89\81[\82ð\95ñ\8d\90\82µ\82Ä\82­\82¾\82³\82¢\81D%s", WIZARD_NAME,
696                        maybe_rebuild);
697 #endif
698     }
699 #endif
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();
705         if (dosave0()) {
706             /* os/win port specific recover instructions */
707             if (sysopt.recover)
708                 raw_printf("%s", sysopt.recover);
709         }
710     }
711 #endif
712     {
713         char buf[BUFSZ];
714
715         Vsprintf(buf, str, VA_ARGS);
716         raw_print(buf);
717         paniclog("panic", buf);
718     }
719 #ifdef WIN32
720     interject(INTERJECT_PANIC);
721 #endif
722 #if defined(UNIX) || defined(VMS) || defined(LATTICE) || defined(WIN32)
723     if (wizard)
724         NH_abort(); /* generate core dump */
725 #endif
726     VA_END();
727     really_done(PANICKED);
728 }
729
730 STATIC_OVL boolean
731 should_query_disclose_option(category, defquery)
732 int category;
733 char *defquery;
734 {
735     int idx;
736     char disclose, *dop;
737
738     *defquery = 'n';
739     if ((dop = index(disclosure_options, category)) != 0) {
740         idx = (int) (dop - disclosure_options);
741         if (idx < 0 || idx >= NUM_DISCLOSURE_OPTIONS) {
742             impossible(
743                    "should_query_disclose_option: bad disclosure index %d %c",
744                        idx, category);
745             *defquery = DISCLOSE_PROMPT_DEFAULT_YES;
746             return TRUE;
747         }
748         disclose = flags.end_disclose[idx];
749         if (disclose == DISCLOSE_YES_WITHOUT_PROMPT) {
750             *defquery = 'y';
751             return FALSE;
752         } else if (disclose == DISCLOSE_SPECIAL_WITHOUT_PROMPT) {
753             *defquery = 'a';
754             return FALSE;
755         } else if (disclose == DISCLOSE_NO_WITHOUT_PROMPT) {
756             *defquery = 'n';
757             return FALSE;
758         } else if (disclose == DISCLOSE_PROMPT_DEFAULT_YES) {
759             *defquery = 'y';
760             return TRUE;
761         } else if (disclose == DISCLOSE_PROMPT_DEFAULT_SPECIAL) {
762             *defquery = 'a';
763             return TRUE;
764         } else {
765             *defquery = 'n';
766             return TRUE;
767         }
768     }
769     impossible("should_query_disclose_option: bad category %c", category);
770     return TRUE;
771 }
772
773 #ifdef DUMPLOG
774 STATIC_OVL void
775 dump_plines()
776 {
777     int i, j;
778     char buf[BUFSZ], **strp;
779     extern char *saved_plines[];
780     extern unsigned saved_pline_index;
781
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];
787         if (*strp) {
788             copynchars(&buf[1], *strp, BUFSZ - 1 - 1);
789             putstr(0, 0, buf);
790 #ifdef FREE_ALL_MEMORY
791             free(*strp), *strp = 0;
792 #endif
793         }
794     }
795 }
796 #endif
797
798 /*ARGSUSED*/
799 STATIC_OVL void
800 dump_everything(how, when)
801 int how;
802 time_t when; /* date+time at end of game */
803 {
804 #ifdef DUMPLOG
805     char pbuf[BUFSZ], datetimebuf[24]; /* [24]: room for 64-bit bogus value */
806
807     dump_redirect(TRUE);
808     if (!iflags.in_dumplog)
809         return;
810
811     init_symbols(); /* revert to default symbol set */
812
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));
818     putstr(0, 0, "");
819
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]);
829     putstr(0, 0, pbuf);
830     putstr(0, 0, "");
831
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,
836             urace.adj,
837             (flags.female && urole.name.f) ? urole.name.f : urole.name.m);
838     putstr(0, 0, pbuf);
839     putstr(0, 0, "");
840
841     dump_map();
842     putstr(0, 0, do_statusline1());
843     putstr(0, 0, do_statusline2());
844     putstr(0, 0, "");
845
846     dump_plines();
847     putstr(0, 0, "");
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);
853     putstr(0, 0, "");
854     list_vanquished('d', FALSE); /* 'd' => 'y' */
855     putstr(0, 0, "");
856     list_genocided('d', FALSE); /* 'd' => 'y' */
857     putstr(0, 0, "");
858     show_conduct((how >= PANICKED) ? 1 : 2);
859     putstr(0, 0, "");
860     show_overview((how >= PANICKED) ? 1 : 2, how);
861     putstr(0, 0, "");
862     dump_redirect(FALSE);
863 #else
864     nhUse(how);
865     nhUse(when);
866 #endif
867 }
868
869 STATIC_OVL void
870 disclose(how, taken)
871 int how;
872 boolean taken;
873 {
874     char c = '\0', defquery;
875     char qbuf[QBUFSZ];
876     boolean ask = FALSE;
877
878     if (invent && !done_stopprint) {
879         if (taken)
880 #if 0 /*JP*/
881             Sprintf(qbuf, "Do you want to see what you had when you %s?",
882                     (how == QUIT) ? "quit" : "died");
883 #else
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¾");
886 #endif
887         else
888 /*JP
889             Strcpy(qbuf, "Do you want your possessions identified?");
890 */
891             Strcpy(qbuf,"\8e\9d\82¿\95¨\82ð\8e¯\95Ê\82µ\82Ü\82·\82©\81H"); 
892
893         ask = should_query_disclose_option('i', &defquery);
894         c = ask ? yn_function(qbuf, ynqchars, defquery) : defquery;
895         if (c == 'y') {
896             /* caller has already ID'd everything */
897             (void) display_inventory((char *) 0, TRUE);
898             container_contents(invent, TRUE, TRUE, FALSE);
899         }
900         if (c == 'q')
901             done_stopprint++;
902     }
903
904     if (!done_stopprint) {
905         ask = should_query_disclose_option('a', &defquery);
906 #if 0 /*JP*/
907         c = ask ? yn_function("Do you want to see your attributes?", ynqchars,
908                               defquery)
909                 : defquery;
910 #else
911         c = ask ? yn_function("\91®\90«\82ð\8c©\82Ü\82·\82©\81H", ynqchars,
912                               defquery)
913                 : defquery;
914 #endif
915         if (c == 'y')
916             enlightenment((BASICENLIGHTENMENT | MAGICENLIGHTENMENT),
917                           (how >= PANICKED) ? ENL_GAMEOVERALIVE
918                                             : ENL_GAMEOVERDEAD);
919         if (c == 'q')
920             done_stopprint++;
921     }
922
923     if (!done_stopprint) {
924         ask = should_query_disclose_option('v', &defquery);
925         list_vanquished(defquery, ask);
926     }
927
928     if (!done_stopprint) {
929         ask = should_query_disclose_option('g', &defquery);
930         list_genocided(defquery, ask);
931     }
932
933     if (!done_stopprint) {
934         ask = should_query_disclose_option('c', &defquery);
935 #if 0 /*JP*/
936         c = ask ? yn_function("Do you want to see your conduct?", ynqchars,
937                               defquery)
938                 : defquery;
939 #else
940         c = ask ? yn_function("\82Ç\82¤\82¢\82¤\8ds\93®\82ð\82Æ\82Á\82½\82©\8c©\82Ü\82·\82©\81H", ynqchars,
941                               defquery)
942                 : defquery;
943 #endif
944         if (c == 'y')
945             show_conduct((how >= PANICKED) ? 1 : 2);
946         if (c == 'q')
947             done_stopprint++;
948     }
949
950     if (!done_stopprint) {
951         ask = should_query_disclose_option('o', &defquery);
952 #if 0 /*JP*/
953         c = ask ? yn_function("Do you want to see the dungeon overview?",
954                               ynqchars, defquery)
955                 : defquery;
956 #else
957         c = ask ? yn_function("\96À\8b{\82Ì\8aT\97v\82ð\8c©\82Ü\82·\82©\81H",
958                               ynqchars, defquery)
959                 : defquery;
960 #endif
961         if (c == 'y')
962             show_overview((how >= PANICKED) ? 1 : 2, how);
963         if (c == 'q')
964             done_stopprint++;
965     }
966 }
967
968 /* try to get the player back in a viable state after being killed */
969 STATIC_OVL void
970 savelife(how)
971 int how;
972 {
973     int uhpmin = max(2 * u.ulevel, 10);
974
975     if (u.uhpmax < uhpmin)
976         u.uhpmax = uhpmin;
977     u.uhp = u.uhpmax;
978     u.uswldtim = 0;
979     if (u.uhunger < 500) {
980         u.uhunger = 500;
981         newuhs(FALSE);
982     }
983     /* cure impending doom of sickness hero won't have time to fix */
984     if ((Sick & TIMEOUT) == 1L) {
985         u.usick_type = 0;
986         set_itimeout(&Sick, 0L);
987     }
988     if (how == CHOKING)
989         init_uhunger();
990 /*JP
991     nomovemsg = "You survived that attempt on your life.";
992 */
993     nomovemsg = "\82 \82È\82½\82Í\90\82«\82È\82ª\82ç\82¦\82½\81D";
994     context.move = 0;
995     if (multi > 0)
996         multi = 0;
997     else
998         multi = -1;
999     if (u.utrap && u.utraptype == TT_LAVA)
1000         u.utrap = 0;
1001     context.botl = 1;
1002     u.ugrave_arise = NON_PM;
1003     HUnchanging = 0L;
1004     curs_on_u();
1005     if (!context.mon_moving)
1006         endmultishot(FALSE);
1007 }
1008
1009 /*
1010  * Get valuables from the given list.  Revised code: the list always remains
1011  * intact.
1012  */
1013 STATIC_OVL void
1014 get_valuables(list)
1015 struct obj *list; /* inventory or container contents */
1016 {
1017     register struct obj *obj;
1018     register int i;
1019
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) {
1025             continue;
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;
1031             } else
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;
1038             } else
1039                 gems[i].count += obj->quan;
1040         }
1041     return;
1042 }
1043
1044 /*
1045  *  Sort collected valuables, most frequent to least.  We could just
1046  *  as easily use qsort, but we don't care about efficiency here.
1047  */
1048 STATIC_OVL void
1049 sort_valuables(list, size)
1050 struct valuable_data list[];
1051 int size; /* max value is less than 20 */
1052 {
1053     register int i, j;
1054     struct valuable_data ltmp;
1055
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)
1063                 break;
1064             else {
1065                 list[j] = list[j - 1];
1066             }
1067         list[j] = ltmp;
1068     }
1069     return;
1070 }
1071
1072 #define CAT_CHECK 2
1073
1074 STATIC_OVL boolean
1075 odds_and_ends(list, what)
1076 struct obj *list;
1077 int what;
1078 {
1079     struct obj *otmp;
1080     for (otmp = list; otmp; otmp = otmp->nobj) {
1081         switch (what) {
1082         case CAT_CHECK: /* Schroedinger's Cat */
1083             /* Ascending is deterministic */
1084             if (SchroedingersBox(otmp))
1085                 return rn2(2);
1086             break;
1087         }
1088         if (Has_contents(otmp))
1089             return odds_and_ends(otmp->cobj, what);
1090     }
1091     return FALSE;
1092 }
1093
1094 /* called twice; first to calculate total, then to list relevant items */
1095 STATIC_OVL void
1096 artifact_score(list, counting, endwin)
1097 struct obj *list;
1098 boolean counting; /* true => add up points; false => display them */
1099 winid endwin;
1100 {
1101     char pbuf[BUFSZ];
1102     struct obj *otmp;
1103     long value, points;
1104     short dummy; /* object type returned by artifact_name() */
1105
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 */
1112             if (counting) {
1113                 nowrap_add(u.urexp, points);
1114             } else {
1115                 makeknown(otmp->otyp);
1116                 otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
1117                 /* assumes artifacts don't have quan > 1 */
1118 #if 0 /*JP*/
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);
1124 #else
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);
1129 #endif
1130                 putstr(endwin, 0, pbuf);
1131             }
1132         }
1133         if (Has_contents(otmp))
1134             artifact_score(otmp->cobj, counting, endwin);
1135     }
1136 }
1137
1138 /* Be careful not to call panic from here! */
1139 void
1140 done(how)
1141 int how;
1142 {
1143     if (how == TRICKED) {
1144         if (killer.name[0]) {
1145             paniclog("trickery", killer.name);
1146             killer.name[0] = 0;
1147         }
1148         if (wizard) {
1149 /*JP
1150             You("are a very tricky wizard, it seems.");
1151 */
1152             You("\82Æ\82Ä\82à\88µ\82¢\82É\82­\82¢wizard\82Ì\82æ\82¤\82¾\81D");
1153             return;
1154         }
1155     }
1156     if (program_state.panicking
1157 #ifdef HANGUPHANDLING
1158         || program_state.done_hup
1159 #endif
1160         ) {
1161         /* skip status update if panicking or disconnected */
1162         context.botl = context.botlx = FALSE;
1163     } else {
1164         /* otherwise force full status update */
1165         context.botlx = TRUE;
1166         bot();
1167     }
1168
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)
1175 /*JP
1176         Strcpy(killer.name, deaths[how]);
1177 */
1178         Strcpy(killer.name, ends[how]);
1179
1180     if (how < PANICKED)
1181         u.umortality++;
1182     if (Lifesaved && (how <= GENOCIDED)) {
1183 /*JP
1184         pline("But wait...");
1185 */
1186         pline("\82¿\82å\82Á\82Æ\82Ü\82Á\82½\81D\81D\81D");
1187         makeknown(AMULET_OF_LIFE_SAVING);
1188 /*JP
1189         Your("medallion %s!", !Blind ? "begins to glow" : "feels warm");
1190 */
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½");
1192         if (how == CHOKING)
1193 /*JP
1194             You("vomit ...");
1195 */
1196             You("\93f\82¢\82½\81D\81D\81D");
1197 /*JP
1198         You_feel("much better!");
1199 */
1200         You("\8bC\95ª\82ª\82æ\82­\82È\82Á\82½\81I");
1201 /*JP
1202         pline_The("medallion crumbles to dust!");
1203 */
1204         pline("\96\82\8f\9c\82¯\82Í\82±\82È\82²\82È\82É\82­\82¾\82¯\82½\81I");
1205         if (uamul)
1206             useup(uamul);
1207
1208         (void) adjattrib(A_CON, -1, TRUE);
1209         savelife(how);
1210         if (how == GENOCIDED) {
1211 /*JP
1212             pline("Unfortunately you are still genocided...");
1213 */
1214             pline("\8ec\94O\82È\82ª\82ç\81C\82 \82È\82½\82Í\8bs\8eE\82³\82ê\82½\82Ü\82Ü\82¾\81D\81D\81D");
1215         } else {
1216             killer.name[0] = 0;
1217             killer.format = 0;
1218             return;
1219         }
1220     }
1221 #if 0 /*JP*/
1222     if ((wizard || discover) && (how <= GENOCIDED)
1223         && !paranoid_query(ParanoidDie, "Die?")) {
1224 #else
1225     if ((wizard || discover) && (how <= GENOCIDED)
1226         && !paranoid_query(ParanoidDie, "\8e\80\82ñ\82Å\82Ý\82é\81H")) {
1227 #endif
1228 /*JP
1229         pline("OK, so you don't %s.", (how == CHOKING) ? "choke" : "die");
1230 */
1231         You("\8e\80\82È\82È\82©\82Á\82½\81D");
1232         savelife(how);
1233         killer.name[0] = 0;
1234         killer.format = 0;
1235         return;
1236     }
1237     really_done(how);
1238 }
1239
1240 /* separated from done() in order to specify the __noreturn__ attribute */
1241 STATIC_OVL void
1242 really_done(how)
1243 int how;
1244 {
1245     boolean taken;
1246     char pbuf[BUFSZ];
1247     winid endwin = WIN_ERR;
1248     boolean bones_ok, have_windows = iflags.window_inited;
1249     struct obj *corpse = (struct obj *) 0;
1250     time_t endtime;
1251     long umoney;
1252     long tmp;
1253
1254     /*
1255      *  The game is now over...
1256      */
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;
1262
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 */
1265     inven_inuse(TRUE);
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);
1272
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);
1278
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.
1283      */
1284     if (moves <= 1 && how < PANICKED) /* You die... --More-- */
1285 /*JP
1286         pline("Do not pass go.  Do not collect 200 %s.", currency(200L));
1287 */
1288         pline("\92\8d\88Ó\88ê\95b\81C\89ö\89ä\88ê\90\81C\8e\80\96S\88ê\95à\81D");
1289
1290     if (have_windows)
1291         wait_synch(); /* flush screen output */
1292 #ifndef NO_SIGNAL
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);
1297 #endif
1298 #endif /* NO_SIGNAL */
1299
1300     bones_ok = (how < GENOCIDED) && can_make_bones();
1301
1302     if (bones_ok && launch_in_progress())
1303         force_launch_placement();
1304
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;
1314
1315     if (how == QUIT) {
1316         killer.format = NO_KILLER_PREFIX;
1317         if (u.uhp < 1) {
1318             how = DIED;
1319             u.umortality++; /* skipped above when how==QUIT */
1320 /*JP
1321             Strcpy(killer.name, "quit while already on Charon's boat");
1322 */
1323             Strcpy(killer.name, "\8eO\93r\82Ì\90ì\82Ì\93n\82µ\91D\82É\8fæ\82Á\82Ä\82¢\82é\8aÔ\82É\94²\82¯\82½");
1324         }
1325     }
1326     if (how == ESCAPED || how == PANICKED)
1327         killer.format = NO_KILLER_PREFIX;
1328
1329     fixup_death(how); /* actually, fixup multi_reason */
1330
1331     if (how != PANICKED) {
1332         /* these affect score and/or bones, but avoid them during panic */
1333         taken = paybill((how == ESCAPED) ? -1 : (how != QUIT));
1334         paygd();
1335         clearpriests();
1336     } else
1337         taken = FALSE; /* lint; assert( !bones_ok ); */
1338
1339     clearlocks();
1340
1341     if (have_windows)
1342         display_nhwindow(WIN_MESSAGE, FALSE);
1343
1344     if (how != PANICKED) {
1345         struct obj *obj;
1346
1347         /*
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.
1351          */
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;
1357         }
1358
1359         if (strcmp(flags.end_disclose, "none"))
1360             disclose(how, taken);
1361
1362         dump_everything(how, endtime);
1363     }
1364
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)
1370         keepdogs(TRUE);
1371
1372     /* finish_paybill should be called after disclosure but before bones */
1373     if (bones_ok && taken)
1374         finish_paybill();
1375
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;
1381
1382         if (!Upolyd) {
1383             /* Base corpse on race when not poly'd since original
1384              * u.umonnum is based on role, and all role monsters
1385              * are human.
1386              */
1387             mnum = (flags.female && urace.femalenum != NON_PM)
1388                        ? urace.femalenum
1389                        : urace.malenum;
1390         }
1391         corpse = mk_named_object(CORPSE, &mons[mnum], u.ux, u.uy, plname);
1392 /*JP
1393         Sprintf(pbuf, "%s, ", plname);
1394 */
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);
1398     }
1399     pbuf[0] = '\0'; /* clear grave text; also lint suppression */
1400
1401     /* calculate score, before creating bones [container gold] */
1402     {
1403         int deepest = deepest_lev_reached(FALSE);
1404
1405         umoney = money_cnt(invent);
1406         tmp = u.umoney0;
1407         umoney += hidden_gold(); /* accumulate gold from containers */
1408         tmp = umoney - tmp;      /* net gain */
1409
1410         if (tmp < 0L)
1411             tmp = 0L;
1412         if (how < PANICKED)
1413             tmp -= tmp / 10L;
1414         tmp += 50L * (long) (deepest - 1);
1415         if (deepest > 20)
1416             tmp += 1000L * (long) ((deepest > 30) ? 10 : deepest - 20);
1417         nowrap_add(u.urexp, tmp);
1418
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])
1424                       ? u.urexp
1425                       : (u.urexp / 2L);
1426             nowrap_add(u.urexp, tmp);
1427         }
1428     }
1429
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 */
1434 /*JP
1435         Your("body rises from the dead as %s...",
1436 */
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);
1440     }
1441
1442     if (bones_ok) {
1443 /*JP
1444         if (!wizard || paranoid_query(ParanoidBones, "Save bones?"))
1445 */
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;
1451     }
1452
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;
1456
1457     /* clean up unneeded windows */
1458     if (have_windows) {
1459         wait_synch();
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;
1465         }
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;
1470 #endif
1471         destroy_nhwindow(WIN_MESSAGE),  WIN_MESSAGE = WIN_ERR;
1472
1473         if (!done_stopprint || flags.tombstone)
1474             endwin = create_nhwindow(NHW_TEXT);
1475
1476         if (how < GENOCIDED && flags.tombstone && endwin != WIN_ERR)
1477             outrip(endwin, how, endtime);
1478     } else
1479         done_stopprint = 1; /* just avoid any more output */
1480
1481 #ifdef DUMPLOG
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);
1489     }
1490 #endif
1491     if (u.uhave.amulet) {
1492 /*JP
1493         Strcat(killer.name, " (with the Amulet)");
1494 */
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 */
1498 /*JP
1499             Strcat(killer.name, " (in celestial disgrace)");
1500 */
1501             Strcat(killer.name, "\93V\8fã\82Å\92p\90J\82ð\8eó\82¯\92E\8fo\82µ\82½");
1502         else if (carrying(FAKE_AMULET_OF_YENDOR))
1503 /*JP
1504             Strcat(killer.name, " (with a fake Amulet)");
1505 */
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 */
1508     }
1509
1510 #if 0 /*JP*/
1511     Sprintf(pbuf, "%s %s the %s...", Goodbye(), plname,
1512             (how != ASCENDED)
1513                 ? (const char *) ((flags.female && urole.name.f)
1514                     ? urole.name.f
1515                     : urole.name.m)
1516                 : (const char *) (flags.female ? "Demigoddess" : "Demigod"));
1517 #else
1518     Sprintf(pbuf, "%s%s\82Ì%s\81D\81D\81D", Goodbye(),
1519             (how != ASCENDED)
1520                 ? (const char *) ((flags.female && urole.name.f)
1521                     ? urole.name.f
1522                     : urole.name.m)
1523                 : (const char *) (flags.female ? "\8f\97\90_" : "\90_"),
1524                 plname);
1525 #endif
1526     dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1527     dump_forward_putstr(endwin, 0, "", done_stopprint);
1528
1529     if (how == ESCAPED || how == ASCENDED) {
1530         struct monst *mtmp;
1531         struct obj *otmp;
1532         register struct val_list *val;
1533         register int i;
1534
1535         for (val = valuables; val->list; val++)
1536             for (i = 0; i < val->size; i++) {
1537                 val->list[i].count = 0L;
1538             }
1539         get_valuables(invent);
1540
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);
1548                 }
1549
1550         /* count the points for artifacts */
1551         artifact_score(invent, TRUE, endwin);
1552
1553         viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */
1554         mtmp = mydogs;
1555 /*JP
1556             Strcpy(pbuf, "You");
1557 */
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]);
1563
1564             mhp = d(m_lev, 8);
1565             nowrap_add(u.urexp, mhp);
1566 /*JP
1567                 Strcat(eos(pbuf), " and Schroedinger's cat");
1568 */
1569                 Strcat(eos(pbuf), "\82Æ\83V\83\85\83\8c\83f\83B\83\93\83K\81[\82Ì\94L");
1570         }
1571         if (mtmp) {
1572             while (mtmp) {
1573 /*JP
1574                     Sprintf(eos(pbuf), " and %s", mon_nam(mtmp));
1575 */
1576                     Sprintf(eos(pbuf), "\82Æ%s", mon_nam(mtmp));
1577                 if (mtmp->mtame)
1578                     nowrap_add(u.urexp, mtmp->mhp);
1579                 mtmp = mtmp->nmon;
1580             }
1581 #if 1 /*JP*/
1582             if (!done_stopprint)
1583                 Strcat(pbuf, "\82Í");
1584 #endif
1585             dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1586             pbuf[0] = '\0';
1587         } else {
1588 /*JP
1589                 Strcat(pbuf, " ");
1590 */
1591                 Strcat(pbuf, "\82Í");
1592         }
1593 #if 0 /*JP*/
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));
1598 #else
1599         Sprintf(eos(pbuf), "%ld\83|\83C\83\93\83g\83}\81[\83N\82µ%s\81D",
1600                 u.urexp,
1601                 how==ASCENDED ? "\8f¸\93V\82µ\82½" : "\96À\8b{\82©\82ç\92E\8fo\82µ\82½");
1602 #endif
1603         dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1604
1605         if (!done_stopprint)
1606             artifact_score(invent, FALSE, endwin); /* list artifacts */
1607 #ifdef DUMPLOG
1608         dump_redirect(TRUE);
1609         if (iflags.in_dumplog)
1610             artifact_score(invent, FALSE, 0);
1611         dump_redirect(FALSE);
1612 #endif
1613
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;
1620
1621                 if (count == 0L)
1622                     continue;
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))
1629                         free_oname(otmp);
1630                     otmp->quan = count;
1631 #if 0 /*JP*/
1632                     Sprintf(pbuf, "%8ld %s (worth %ld %s),", count,
1633                             xname(otmp), count * (long) objects[typ].oc_cost,
1634                             currency(2L));
1635 #else
1636                     Sprintf(pbuf, "%ld\8cÂ\82Ì%s(%ld%s\82Ì\89¿\92l)\81C", count,
1637                             xname(otmp), count * (long) objects[typ].oc_cost,
1638                             currency(2L));
1639 #endif
1640                     obfree(otmp, (struct obj *) 0);
1641                 } else {
1642 #if 0 /*JP*/
1643                     Sprintf(pbuf, "%8ld worthless piece%s of colored glass,",
1644                             count, plur(count));
1645 #else
1646                     Sprintf(pbuf, "%ld\8cÂ\82Ì\89¿\92l\82Ì\82È\82¢\90F\82Â\82«\83K\83\89\83X\81C",
1647                             count);
1648 #endif
1649                 }
1650                 dump_forward_putstr(endwin, 0, pbuf, 0);
1651             }
1652         }
1653
1654     } else {
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" */
1659 #if 0 /*JP*/
1660             Sprintf(pbuf, "You %s beyond the confines of the dungeon",
1661                     (u.uz.dlevel < 0) ? "passed away" : ends[how]);
1662 #else
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]);
1665 #endif
1666         } else {
1667             /* more conventional demise */
1668             const char *where = dungeons[u.uz.dnum].dname;
1669
1670             if (Is_astralevel(&u.uz))
1671 /*JP
1672                 where = "The Astral Plane";
1673 */
1674                 where = "\90¸\97ì\8aE\82É\82Ä";
1675 /*JP
1676             Sprintf(pbuf, "You %s in %s", ends[how], where);
1677 */
1678             Sprintf(pbuf, "\82 \82È\82½\82Í%s", where);
1679             if (!In_endgame(&u.uz) && !Is_knox(&u.uz))
1680 #if 0 /*JP*/
1681                 Sprintf(eos(pbuf), " on dungeon level %d",
1682                         In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz));
1683 #else
1684                 Sprintf(eos(pbuf), "\82Ì\92n\89º%d\8aK\82Å",
1685                         In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz));
1686 #endif
1687         }
1688
1689 /*JP
1690         Sprintf(eos(pbuf), " with %ld point%s,", u.urexp, plur(u.urexp));
1691 */
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);
1694     }
1695
1696 #if 0 /*JP:T*/
1697     Sprintf(pbuf, "and %ld piece%s of gold, after %ld move%s.", umoney,
1698             plur(umoney), moves, plur(moves));
1699 #else
1700     Sprintf(pbuf, "%ld\96\87\82Ì\8bà\89Ý\82ð\8e\9d\82Á\82Ä\81C%ld\95à\93®\82¢\82½\81D", umoney,
1701             moves);
1702 #endif
1703     dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1704 #if 0 /*JP:T*/
1705     Sprintf(pbuf,
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]);
1708 #else
1709     Sprintf(pbuf,
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);
1712 #endif
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);
1719
1720     dump_close_log();
1721     /* "So when I die, the first thing I will see in Heaven is a
1722      * score list?" */
1723     if (have_windows && !iflags.toptenwin)
1724         exit_nhwindows((char *) 0), have_windows = FALSE;
1725     topten(how, endtime);
1726     if (have_windows)
1727         exit_nhwindows((char *) 0);
1728
1729     if (done_stopprint) {
1730         raw_print("");
1731         raw_print("");
1732     }
1733     nh_terminate(EXIT_SUCCESS);
1734 }
1735
1736 void
1737 container_contents(list, identified, all_containers, reportempty)
1738 struct obj *list;
1739 boolean identified, all_containers, reportempty;
1740 {
1741     register struct obj *box, *obj;
1742     char buf[BUFSZ];
1743     boolean cat, deadcat;
1744
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 */
1748             if (identified)
1749                 box->lknown = 1;
1750             cat = deadcat = FALSE;
1751             if (SchroedingersBox(box) && !Schroedingers_cat) {
1752                 /* Schroedinger's Cat? */
1753                 cat = odds_and_ends(box, CAT_CHECK);
1754                 if (cat)
1755                     Schroedingers_cat = TRUE;
1756                 else
1757                     deadcat = TRUE;
1758                 box->spe = 0;
1759             }
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);
1764
1765                 sortloot(&box->cobj,
1766                          (((flags.sortloot == 'l' || flags.sortloot == 'f')
1767                            ? SORTLOOT_LOOT : 0)
1768                           | (flags.sortpack ? SORTLOOT_PACK : 0)),
1769                          FALSE);
1770 /*JP
1771                 Sprintf(buf, "Contents of %s:", the(xname(box)));
1772 */
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) {
1777                     if (identified) {
1778                         makeknown(obj->otyp);
1779                         obj->known = obj->bknown = obj->dknown
1780                             = obj->rknown = 1;
1781                         if (Is_container(obj) || obj->otyp == STATUE)
1782                             obj->cknown = obj->lknown = 1;
1783                     }
1784                     putstr(tmpwin, 0, doname(obj));
1785                 }
1786                 if (cat)
1787 /*JP
1788                     putstr(tmpwin, 0, "Schroedinger's cat");
1789 */
1790                     putstr(tmpwin, 0, "\83V\83\85\83\8c\83f\83B\83\93\83K\81[\82Ì\94L");
1791                 else if (deadcat)
1792 /*JP
1793                     putstr(tmpwin, 0, "Schroedinger's dead cat");
1794 */
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);
1798                 if (all_containers)
1799                     container_contents(box->cobj, identified, TRUE,
1800                                        reportempty);
1801             } else if (cat || deadcat) {
1802 #if 0 /*JP*/
1803                 pline("%s Schroedinger's %scat!", Tobjnam(box, "contain"),
1804                       deadcat ? "dead " : "");
1805 #else
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Ì" : "");
1808 #endif
1809                 display_nhwindow(WIN_MESSAGE, FALSE);
1810             } else if (reportempty) {
1811 /*JP
1812                 pline("%s is empty.", upstart(thesimpleoname(box)));
1813 */
1814                 pline("%s\82Í\8bó\82Á\82Û\82¾\81D", xname(box));
1815                 display_nhwindow(WIN_MESSAGE, FALSE);
1816             }
1817         }
1818         if (!all_containers)
1819             break;
1820     }
1821 }
1822
1823 /* should be called with either EXIT_SUCCESS or EXIT_FAILURE */
1824 void
1825 nh_terminate(status)
1826 int status;
1827 {
1828     program_state.in_moveloop = 0; /* won't be returning to normal play */
1829 #ifdef MAC
1830     getreturn("to exit");
1831 #endif
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) {
1835         freedynamicdata();
1836         dlb_cleanup();
1837     }
1838
1839 #ifdef VMS
1840     /*
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.
1844      */
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)
1848         return;
1849 #endif
1850     program_state.exiting = 1;
1851 #if 1 /*JP*/
1852     jputchar('\0'); /* reset terminal */
1853 #endif
1854     nethack_exit(status);
1855 }
1856
1857 extern const int monstr[];
1858
1859 enum vanq_order_modes {
1860     VANQ_MLVL_MNDX = 0,
1861     VANQ_MSTR_MNDX,
1862     VANQ_ALPHA_SEP,
1863     VANQ_ALPHA_MIX,
1864     VANQ_MCLS_HTOL,
1865     VANQ_MCLS_LTOH,
1866     VANQ_COUNT_H_L,
1867     VANQ_COUNT_L_H,
1868
1869     NUM_VANQ_ORDER_MODES
1870 };
1871
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",
1881 };
1882 static int vanq_sortmode = VANQ_MLVL_MNDX;
1883
1884 STATIC_PTR int CFDECLSPEC
1885 vanqsort_cmp(vptr1, vptr2)
1886 const genericptr vptr1;
1887 const genericptr vptr2;
1888 {
1889     int indx1 = *(short *) vptr1, indx2 = *(short *) vptr2,
1890         mlev1, mlev2, mstr1, mstr2, uniq1, uniq2, died1, died2, res;
1891     const char *name1, *name2, *punct;
1892     schar mcls1, mcls2;
1893
1894     switch (vanq_sortmode) {
1895     default:
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 */
1900         break;
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 */
1905         break;
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;
1911             break;
1912         } /* else both unique or neither unique */
1913         /*FALLTHRU*/
1914     case VANQ_ALPHA_MIX:
1915         name1 = mons[indx1].mname, name2 = mons[indx2].mname;
1916         res = strcmpi(name1, name2); /* caseblind alhpa, low to high */
1917         break;
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'
1935             };
1936
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));
1941         }
1942         res = mcls1 - mcls2; /* class */
1943         if (res == 0) {
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 */
1948         }
1949         break;
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 */
1956         break;
1957     }
1958     /* tiebreaker: internal mons[] index */
1959     if (res == 0)
1960         res = indx1 - indx2; /* mndx low to high */
1961     return res;
1962 }
1963
1964 /* returns -1 if cancelled via ESC */
1965 STATIC_OVL int
1966 set_vanq_order()
1967 {
1968     winid tmpwin;
1969     menu_item *selected;
1970     anything any;
1971     int i, n, choice;
1972
1973     tmpwin = create_nhwindow(NHW_MENU);
1974     start_menu(tmpwin);
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 */
1978             continue;
1979         any.a_int = i + 1;
1980         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, vanqorders[i],
1981                  (i == vanq_sortmode) ? MENU_SELECTED : MENU_UNSELECTED);
1982     }
1983     end_menu(tmpwin, "Sort order for vanquished monster counts");
1984
1985     n = select_menu(tmpwin, PICK_ONE, &selected);
1986     destroy_nhwindow(tmpwin);
1987     if (n > 0) {
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;
1994     }
1995     return (n < 0) ? -1 : vanq_sortmode;
1996 }
1997
1998 /* #vanquished command */
1999 int
2000 dovanquished()
2001 {
2002     list_vanquished('a', FALSE);
2003     return 0;
2004 }
2005
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)
2009
2010 STATIC_OVL void
2011 list_vanquished(defquery, ask)
2012 char defquery;
2013 boolean ask;
2014 {
2015     register int i;
2016     int pfx, nkilled;
2017     unsigned ntypes, ni;
2018     long total_killed = 0L;
2019     winid klwin;
2020     short mindx[NUMMONS];
2021     char c, buf[BUFSZ], buftoo[BUFSZ];
2022     boolean dumping; /* for DUMPLOG; doesn't need to be conditional */
2023
2024     dumping = (defquery == 'd');
2025     if (dumping)
2026         defquery = 'y';
2027
2028     /* get totals first */
2029     ntypes = 0;
2030     for (i = LOW_PM; i < NUMMONS; i++) {
2031         if ((nkilled = (int) mvitals[i].died) == 0)
2032             continue;
2033         mindx[ntypes++] = i;
2034         total_killed += (long) nkilled;
2035     }
2036
2037     /* vanquished creatures list;
2038      * includes all dead monsters, not just those killed by the player
2039      */
2040     if (ntypes != 0) {
2041         char mlet, prev_mlet = 0; /* used as small integer, not character */
2042         boolean class_header, uniq_header, was_uniq = FALSE;
2043
2044 #if 0 /*JP:T*/
2045         c = ask ? yn_function(
2046                             "Do you want an account of creatures vanquished?",
2047                               ynaqchars, defquery)
2048                 : defquery;
2049 #else
2050         c = ask ? yn_function(
2051                             "\93|\82µ\82½\93G\82Ì\88ê\97\97\82ð\8c©\82Ü\82·\82©\81H",
2052                               ynqchars, defquery)
2053                 : defquery;
2054 #endif
2055         if (c == 'q')
2056             done_stopprint++;
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)
2062                     return;
2063             }
2064             uniq_header = (vanq_sortmode == VANQ_ALPHA_SEP);
2065             class_header = (vanq_sortmode == VANQ_MCLS_LTOH
2066                             || vanq_sortmode == VANQ_MCLS_HTOL);
2067
2068             klwin = create_nhwindow(NHW_MENU);
2069 /*JP
2070             putstr(klwin, 0, "Vanquished creatures:");
2071 */
2072             putstr(klwin, 0, "\93|\82µ\82½\93G\81F");
2073             if (!dumping)
2074                 putstr(klwin, 0, "");
2075
2076             qsort((genericptr_t) mindx, ntypes, sizeof *mindx, vanqsort_cmp);
2077             for (ni = 0; ni < ntypes; ni++) {
2078                 i = mindx[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,
2084                            upstart(buf));
2085                     prev_mlet = mlet;
2086                 }
2087                 if (UniqCritterIndx(i)) {
2088 #if 0 /*JP*/
2089                     Sprintf(buf, "%s%s",
2090                             !type_is_pname(&mons[i]) ? "the " : "",
2091                             mons[i].mname);
2092 #else
2093                     Sprintf(buf, "%s", mons[i].mname);
2094 #endif
2095                     if (nkilled > 1) {
2096 #if 0 /*JP*/
2097                         switch (nkilled) {
2098                         case 2:
2099                             Sprintf(eos(buf), " (twice)");
2100                             break;
2101                         case 3:
2102                             Sprintf(eos(buf), " (thrice)");
2103                             break;
2104                         default:
2105                             Sprintf(eos(buf), " (%d times)", nkilled);
2106                             break;
2107                         }
2108 #else
2109                         Sprintf(eos(buf)," (%d\89ñ)", nkilled);
2110 #endif
2111                     }
2112                     was_uniq = TRUE;
2113                 } else {
2114                     if (uniq_header && was_uniq) {
2115                         putstr(klwin, 0, "");
2116                         was_uniq = FALSE;
2117                     }
2118                     /* trolls or undead might have come back,
2119                        but we don't keep track of that */
2120                     if (nkilled == 1)
2121                         Strcpy(buf, an(mons[i].mname));
2122                     else
2123 #if 0 /*JP:T*/
2124                         Sprintf(buf, "%3d %s", nkilled,
2125                                 makeplural(mons[i].mname));
2126 #else
2127                         Sprintf(buf, "%d\91Ì\82Ì%s", nkilled,
2128                                 mons[i].mname);
2129 #endif
2130                 }
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;
2136                 if (class_header)
2137                     ++pfx;
2138                 Sprintf(buftoo, "%*s%s", pfx, "", buf);
2139                 putstr(klwin, 0, buftoo);
2140             }
2141             /*
2142              * if (Hallucination)
2143              *     putstr(klwin, 0, "and a partridge in a pear tree");
2144              */
2145             if (ntypes > 1) {
2146                 if (!dumping)
2147                     putstr(klwin, 0, "");
2148 /*JP
2149                 Sprintf(buf, "%ld creatures vanquished.", total_killed);
2150 */
2151                 Sprintf(buf, "%ld\95C\82Ì\93G\82ð\93|\82µ\82½\81D", total_killed);
2152                 putstr(klwin, 0, buf);
2153             }
2154             display_nhwindow(klwin, TRUE);
2155             destroy_nhwindow(klwin);
2156         }
2157     } else if (defquery == 'a') {
2158         /* #dovanquished rather than final disclosure, so pline() is ok */
2159 /*JP
2160         pline("No creatures have been vanquished.");
2161 */
2162         pline("\93|\82µ\82½\93G\82Í\82¢\82È\82©\82Á\82½\81D");
2163 #ifdef DUMPLOG
2164     } else if (dumping) {
2165         putstr(0, 0, "No creatures were vanquished."); /* not pline() */
2166 #endif
2167     }
2168 }
2169
2170 /* number of monster species which have been genocided */
2171 int
2172 num_genocides()
2173 {
2174     int i, n = 0;
2175
2176     for (i = LOW_PM; i < NUMMONS; ++i) {
2177         if (mvitals[i].mvflags & G_GENOD) {
2178             ++n;
2179             if (UniqCritterIndx(i))
2180                 impossible("unique creature '%d: %s' genocided?",
2181                            i, mons[i].mname);
2182         }
2183     }
2184     return n;
2185 }
2186
2187 STATIC_OVL int
2188 num_extinct()
2189 {
2190     int i, n = 0;
2191
2192     for (i = LOW_PM; i < NUMMONS; ++i) {
2193         if (UniqCritterIndx(i))
2194             continue;
2195         if ((mvitals[i].mvflags & G_GONE) == G_EXTINCT)
2196             ++n;
2197     }
2198     return n;
2199 }
2200
2201 STATIC_OVL void
2202 list_genocided(defquery, ask)
2203 char defquery;
2204 boolean ask;
2205 {
2206     register int i;
2207     int ngenocided, nextinct;
2208     char c;
2209     winid klwin;
2210     char buf[BUFSZ];
2211     boolean dumping; /* for DUMPLOG; doesn't need to be conditional */
2212
2213     dumping = (defquery == 'd');
2214     if (dumping)
2215         defquery = 'y';
2216
2217     ngenocided = num_genocides();
2218     nextinct = num_extinct();
2219
2220     /* genocided or extinct species list */
2221     if (ngenocided != 0 || nextinct != 0) {
2222 #if 0 /*JP:T*/
2223         Sprintf(buf, "Do you want a list of %sspecies%s%s?",
2224                 (nextinct && !ngenocided) ? "extinct " : "",
2225                 (ngenocided) ? " genocided" : "",
2226                 (nextinct && ngenocided) ? " and extinct" : "");
2227 #else
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Å" : "");
2232 #endif
2233         c = ask ? yn_function(buf, ynqchars, defquery) : defquery;
2234         if (c == 'q')
2235             done_stopprint++;
2236         if (c == 'y') {
2237             klwin = create_nhwindow(NHW_MENU);
2238 #if 0 /*JP*/
2239             Sprintf(buf, "%s%s species:",
2240                     (ngenocided) ? "Genocided" : "Extinct",
2241                     (nextinct && ngenocided) ? " or extinct" : "");
2242 #else
2243             Sprintf(buf, "%s%s\82µ\82½\8eí:",
2244                     (ngenocided) ? "\8bs\8eE" : "\90â\96Å",
2245                     (nextinct && ngenocided) ? "\82Ü\82½\82Í\90â\96Å" : "");
2246 #endif
2247             putstr(klwin, 0, buf);
2248             if (!dumping)
2249                 putstr(klwin, 0, "");
2250
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))
2255                     continue;
2256                 if (mvitals[i].mvflags & G_GONE) {
2257                     Sprintf(buf, " %s", makeplural(mons[i].mname));
2258                     /*
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.
2263                      */
2264                     if ((mvitals[i].mvflags & G_GONE) == G_EXTINCT)
2265 /*JP
2266                         Strcat(buf, " (extinct)");
2267 */
2268                         Strcat(buf, "(\90â\96Å)");
2269                     putstr(klwin, 0, buf);
2270                 }
2271             }
2272             if (!dumping)
2273                 putstr(klwin, 0, "");
2274             if (ngenocided > 0) {
2275 /*JP
2276                 Sprintf(buf, "%d species genocided.", ngenocided);
2277 */
2278                 Sprintf(buf, "%d\8eí\97Þ\82Ì\8eí\82ð\8bs\8eE\82µ\82½\81D", ngenocided);
2279                 putstr(klwin, 0, buf);
2280             }
2281             if (nextinct > 0) {
2282 /*JP
2283                 Sprintf(buf, "%d species extinct.", nextinct);
2284 */
2285                 Sprintf(buf, "%d\8eí\97Þ\82Ì\8eí\82ð\90â\96Å\82³\82¹\82½\81D", nextinct);
2286                 putstr(klwin, 0, buf);
2287             }
2288
2289             display_nhwindow(klwin, TRUE);
2290             destroy_nhwindow(klwin);
2291         }
2292 #ifdef DUMPLOG
2293     } else if (dumping) {
2294         putstr(0, 0, "No species were genocided or became extinct.");
2295 #endif
2296     }
2297 }
2298
2299 /* set a delayed killer, ensure non-delayed killer is cleared out */
2300 void
2301 delayed_killer(id, format, killername)
2302 int id;
2303 int format;
2304 const char *killername;
2305 {
2306     struct kinfo *k = find_delayed_killer(id);
2307
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));
2312         k->id = id;
2313         k->next = killer.next;
2314         killer.next = k;
2315     }
2316
2317     k->format = format;
2318     Strcpy(k->name, killername ? killername : "");
2319     killer.name[0] = 0;
2320 }
2321
2322 struct kinfo *
2323 find_delayed_killer(id)
2324 int id;
2325 {
2326     struct kinfo *k;
2327
2328     for (k = killer.next; k != (struct kinfo *) 0; k = k->next) {
2329         if (k->id == id)
2330             break;
2331     }
2332     return k;
2333 }
2334
2335 void
2336 dealloc_killer(kptr)
2337 struct kinfo *kptr;
2338 {
2339     struct kinfo *prev = &killer, *k;
2340
2341     if (kptr == (struct kinfo *) 0)
2342         return;
2343     for (k = killer.next; k != (struct kinfo *) 0; k = k->next) {
2344         if (k == kptr)
2345             break;
2346         prev = k;
2347     }
2348
2349     if (k == (struct kinfo *) 0) {
2350         impossible("dealloc_killer not on list");
2351     } else {
2352         prev->next = k->next;
2353         free((genericptr_t) k);
2354     }
2355 }
2356
2357 void
2358 save_killers(fd, mode)
2359 int fd;
2360 int mode;
2361 {
2362     struct kinfo *kptr;
2363
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));
2367         }
2368     }
2369     if (release_data(mode)) {
2370         while (killer.next) {
2371             kptr = killer.next->next;
2372             free((genericptr_t) killer.next);
2373             killer.next = kptr;
2374         }
2375     }
2376 }
2377
2378 void
2379 restore_killers(fd)
2380 int fd;
2381 {
2382     struct kinfo *kptr;
2383
2384     for (kptr = &killer; kptr != (struct kinfo *) 0; kptr = kptr->next) {
2385         mread(fd, (genericptr_t) kptr, sizeof(struct kinfo));
2386         if (kptr->next) {
2387             kptr->next = (struct kinfo *) alloc(sizeof(struct kinfo));
2388         }
2389     }
2390 }
2391
2392 static int
2393 wordcount(p)
2394 char *p;
2395 {
2396     int words = 0;
2397
2398     while (*p) {
2399         while (*p && isspace((uchar) *p))
2400             p++;
2401         if (*p)
2402             words++;
2403         while (*p && !isspace((uchar) *p))
2404             p++;
2405     }
2406     return words;
2407 }
2408
2409 static void
2410 bel_copy1(inp, out)
2411 char **inp, *out;
2412 {
2413     char *in = *inp;
2414
2415     out += strlen(out); /* eos() */
2416     while (*in && isspace((uchar) *in))
2417         in++;
2418     while (*in && !isspace((uchar) *in))
2419         *out++ = *in++;
2420     *out = '\0';
2421     *inp = in;
2422 }
2423
2424 char *
2425 build_english_list(in)
2426 char *in;
2427 {
2428     char *out, *p = in;
2429     int len = (int) strlen(p), words = wordcount(p);
2430
2431     /* +3: " or " - " "; +(words - 1): (N-1)*(", " - " ") */
2432     if (words > 1)
2433         len += 3 + (words - 1);
2434     out = (char *) alloc(len + 1);
2435     *out = '\0'; /* bel_copy1() appends */
2436
2437     switch (words) {
2438     case 0:
2439         impossible("no words in list");
2440         break;
2441     case 1:
2442         /* "single" */
2443         bel_copy1(&p, out);
2444         break;
2445     default:
2446         if (words == 2) {
2447             /* "first or second" */
2448             bel_copy1(&p, out);
2449             Strcat(out, " ");
2450         } else {
2451             /* "first, second, or third */
2452             do {
2453                 bel_copy1(&p, out);
2454                 Strcat(out, ", ");
2455             } while (--words > 1);
2456         }
2457         Strcat(out, "or ");
2458         bel_copy1(&p, out);
2459         break;
2460     }
2461     return out;
2462 }
2463
2464 /*end.c*/