OSDN Git Service

fix #36659
[jnethack/source.git] / src / end.c
1 /* NetHack 3.6  end.c   $NHDT-Date: 1448241780 2015/11/23 01:23:00 $  $NHDT-Branch: master $:$NHDT-Revision: 1.108 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 #define NEED_VARARGS /* comment line for pre-compiled headers */
6
7 #include "hack.h"
8 #include "lev.h"
9 #ifndef NO_SIGNAL
10 #include <signal.h>
11 #endif
12 #include <ctype.h>
13 #include <limits.h>
14 #include "dlb.h"
15
16 /* add b to long a, convert wraparound to max value */
17 #define nowrap_add(a, b) (a = ((a + b) < 0 ? LONG_MAX : (a + b)))
18
19 /* these probably ought to be generated by makedefs, like LAST_GEM */
20 #define FIRST_GEM DILITHIUM_CRYSTAL
21 #define FIRST_AMULET AMULET_OF_ESP
22 #define LAST_AMULET AMULET_OF_YENDOR
23
24 struct valuable_data {
25     long count;
26     int typ;
27 };
28
29 static struct valuable_data
30     gems[LAST_GEM + 1 - FIRST_GEM + 1], /* 1 extra for glass */
31     amulets[LAST_AMULET + 1 - FIRST_AMULET];
32
33 static struct val_list {
34     struct valuable_data *list;
35     int size;
36 } valuables[] = { { gems, sizeof gems / sizeof *gems },
37                   { amulets, sizeof amulets / sizeof *amulets },
38                   { 0, 0 } };
39
40 #ifndef NO_SIGNAL
41 STATIC_PTR void FDECL(done_intr, (int));
42 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
43 static void FDECL(done_hangup, (int));
44 #endif
45 #endif
46 STATIC_DCL void FDECL(disclose, (int, BOOLEAN_P));
47 STATIC_DCL void FDECL(get_valuables, (struct obj *));
48 STATIC_DCL void FDECL(sort_valuables, (struct valuable_data *, int));
49 STATIC_DCL void FDECL(artifact_score, (struct obj *, BOOLEAN_P, winid));
50 STATIC_DCL void FDECL(really_done, (int)) NORETURN;
51 STATIC_DCL boolean FDECL(odds_and_ends, (struct obj *, int));
52 STATIC_DCL void FDECL(savelife, (int));
53 STATIC_DCL void FDECL(list_vanquished, (CHAR_P, BOOLEAN_P));
54 STATIC_DCL void FDECL(list_genocided, (CHAR_P, BOOLEAN_P));
55 STATIC_DCL boolean FDECL(should_query_disclose_option, (int, char *));
56 STATIC_DCL int NDECL(num_extinct);
57
58 #if defined(__BEOS__) || defined(MICRO) || defined(WIN32) || defined(OS2)
59 extern void FDECL(nethack_exit, (int));
60 #else
61 #define nethack_exit exit
62 #endif
63
64 #define done_stopprint program_state.stopprint
65
66 #ifndef PANICTRACE
67 #define NH_abort NH_abort_
68 #endif
69
70 #ifdef AMIGA
71 #define NH_abort_() Abort(0)
72 #else
73 #ifdef SYSV
74 #define NH_abort_() (void) abort()
75 #else
76 #ifdef WIN32
77 #define NH_abort_() win32_abort()
78 #else
79 #define NH_abort_() abort()
80 #endif
81 #endif /* !SYSV */
82 #endif /* !AMIGA */
83
84 #ifdef PANICTRACE
85 #include <errno.h>
86 #ifdef PANICTRACE_LIBC
87 #include <execinfo.h>
88 #endif
89
90 /* What do we try and in what order?  Tradeoffs:
91  * libc: +no external programs required
92  *        -requires newish libc/glibc
93  *        -requires -rdynamic
94  * gdb:   +gives more detailed information
95  *        +works on more OS versions
96  *        -requires -g, which may preclude -O on some compilers
97  */
98 #ifdef SYSCF
99 #define SYSOPT_PANICTRACE_GDB sysopt.panictrace_gdb
100 #ifdef PANICTRACE_LIBC
101 #define SYSOPT_PANICTRACE_LIBC sysopt.panictrace_libc
102 #else
103 #define SYSOPT_PANICTRACE_LIBC 0
104 #endif
105 #else
106 #define SYSOPT_PANICTRACE_GDB (nh_getenv("NETHACK_USE_GDB") == 0 ? 0 : 2)
107 #ifdef PANICTRACE_LIBC
108 #define SYSOPT_PANICTRACE_LIBC 1
109 #else
110 #define SYSOPT_PANICTRACE_LIBC 0
111 #endif
112 #endif
113
114 static void NDECL(NH_abort);
115 #ifndef NO_SIGNAL
116 static void FDECL(panictrace_handler, (int));
117 #endif
118 static boolean NDECL(NH_panictrace_libc);
119 static boolean NDECL(NH_panictrace_gdb);
120
121 #ifndef NO_SIGNAL
122 /*ARGSUSED*/
123 void panictrace_handler(
124     sig_unused) /* called as signal() handler, so sent at least one arg */
125 int sig_unused UNUSED;
126 {
127 #define SIG_MSG "\nSignal received.\n"
128     (void) write(2, SIG_MSG, sizeof(SIG_MSG) - 1);
129     NH_abort();
130 }
131
132 void
133 panictrace_setsignals(set)
134 boolean set;
135 {
136 #define SETSIGNAL(sig) \
137     (void) signal(sig, set ? (SIG_RET_TYPE) panictrace_handler : SIG_DFL);
138 #ifdef SIGILL
139     SETSIGNAL(SIGILL);
140 #endif
141 #ifdef SIGTRAP
142     SETSIGNAL(SIGTRAP);
143 #endif
144 #ifdef SIGIOT
145     SETSIGNAL(SIGIOT);
146 #endif
147 #ifdef SIGBUS
148     SETSIGNAL(SIGBUS);
149 #endif
150 #ifdef SIGFPE
151     SETSIGNAL(SIGFPE);
152 #endif
153 #ifdef SIGSEGV
154     SETSIGNAL(SIGSEGV);
155 #endif
156 #ifdef SIGSTKFLT
157     SETSIGNAL(SIGSTKFLT);
158 #endif
159 #ifdef SIGSYS
160     SETSIGNAL(SIGSYS);
161 #endif
162 #ifdef SIGEMT
163     SETSIGNAL(SIGEMT);
164 #endif
165 #undef SETSIGNAL
166 }
167 #endif /* NO_SIGNAL */
168
169 static void
170 NH_abort()
171 {
172     int gdb_prio = SYSOPT_PANICTRACE_GDB;
173     int libc_prio = SYSOPT_PANICTRACE_LIBC;
174     static boolean aborting = FALSE;
175
176     if (aborting)
177         return;
178     aborting = TRUE;
179
180 #ifndef VMS
181     if (gdb_prio == libc_prio && gdb_prio > 0)
182         gdb_prio++;
183
184     if (gdb_prio > libc_prio) {
185         NH_panictrace_gdb() || (libc_prio && NH_panictrace_libc());
186     } else {
187         NH_panictrace_libc() || (gdb_prio && NH_panictrace_gdb());
188     }
189
190 #else /* VMS */
191     /* overload otherwise unused priority for debug mode: 1 = show
192        traceback and exit; 2 = show traceback and stay in debugger */
193     /* if (wizard && gdb_prio == 1) gdb_prio = 2; */
194     vms_traceback(gdb_prio);
195     (void) libc_prio; /* half-hearted attempt at lint suppression */
196
197 #endif /* ?VMS */
198
199 #ifndef NO_SIGNAL
200     panictrace_setsignals(FALSE);
201 #endif
202     NH_abort_();
203 }
204
205 static boolean
206 NH_panictrace_libc()
207 {
208 #ifdef PANICTRACE_LIBC
209     void *bt[20];
210     size_t count, x;
211     char **info;
212
213     raw_print("Generating more information you may report:\n");
214     count = backtrace(bt, SIZE(bt));
215     info = backtrace_symbols(bt, count);
216     for (x = 0; x < count; x++) {
217         raw_printf("[%lu] %s", (unsigned long) x, info[x]);
218     }
219     /* free(info);   -- Don't risk it. */
220     return TRUE;
221 #else
222     return FALSE;
223 #endif /* !PANICTRACE_LIBC */
224 }
225
226 /*
227  *   fooPATH  file system path for foo
228  *   fooVAR   (possibly const) variable containing fooPATH
229  */
230 #ifdef PANICTRACE_GDB
231 #ifdef SYSCF
232 #define GDBVAR sysopt.gdbpath
233 #define GREPVAR sysopt.greppath
234 #else /* SYSCF */
235 #define GDBVAR GDBPATH
236 #define GREPVAR GREPPATH
237 #endif /* SYSCF */
238 #endif /* PANICTRACE_GDB */
239
240 static boolean
241 NH_panictrace_gdb()
242 {
243 #ifdef PANICTRACE_GDB
244     /* A (more) generic method to get a stack trace - invoke
245      * gdb on ourself. */
246     char *gdbpath = GDBVAR;
247     char *greppath = GREPVAR;
248     char buf[BUFSZ];
249     FILE *gdb;
250
251     if (gdbpath == NULL || gdbpath[0] == 0)
252         return FALSE;
253     if (greppath == NULL || greppath[0] == 0)
254         return FALSE;
255
256     sprintf(buf, "%s -n -q %s %d 2>&1 | %s '^#'", gdbpath, ARGV0, getpid(),
257             greppath);
258     gdb = popen(buf, "w");
259     if (gdb) {
260         raw_print("Generating more information you may report:\n");
261         fprintf(gdb, "bt\nquit\ny");
262         fflush(gdb);
263         sleep(4); /* ugly */
264         pclose(gdb);
265         return TRUE;
266     } else {
267         return FALSE;
268     }
269 #else
270     return FALSE;
271 #endif /* !PANICTRACE_GDB */
272 }
273 #endif /* PANICTRACE */
274
275 #if 0 /*JP*//*\93ú\96{\8cê\82Å\82Í\8eg\82í\82È\82¢*/
276 /*
277  * The order of these needs to match the macros in hack.h.
278  */
279 static NEARDATA const char *deaths[] = {
280     /* the array of death */
281     "died", "choked", "poisoned", "starvation", "drowning", "burning",
282     "dissolving under the heat and pressure", "crushed", "turned to stone",
283     "turned into slime", "genocided", "panic", "trickery", "quit",
284     "escaped", "ascended"
285 };
286 #endif /*JP*/
287
288 static NEARDATA const char *ends[] = {
289     /* "when you %s" */
290 #if 0 /*JP*/
291     "died", "choked", "were poisoned",
292     "starved", "drowned", "burned",
293     "dissolved in the lava",
294     "were crushed", "turned to stone",
295     "turned into slime", "were genocided",
296     "panicked", "were tricked", "quit",
297     "escaped", "ascended"
298 #else /*JP: \8dÅ\8cã\82É\81u\8eE\82³\82ê\82½\81v\92Ç\89Á */
299     "\8e\80\82ñ\82¾", "\92\82\91§\82µ\82½", "\93Å\82É\82¨\82©\82³\82ê\82½",
300     "\89ì\8e\80\82µ\82½", "\93M\8e\80\82µ\82½", "\8fÄ\8e\80\82µ\82½",
301     "\97n\8aâ\82É\97n\82¯\82½",
302     "\89\9f\82µ\92×\82³\82ê\82½", "\90Î\82É\82È\82Á\82½",
303     "\82Ç\82ë\82Ç\82ë\82É\97n\82¯\82½", "\8bs\8eE\82³\82ê\82½",
304     "\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½",
305     "\92E\8fo\82µ\82½", "\8f¸\93V\82µ\82½", "\8eE\82³\82ê\82½"
306 #endif
307 };
308
309 static boolean Schroedingers_cat = FALSE;
310
311 /*ARGSUSED*/
312 void
313 done1(sig_unused) /* called as signal() handler, so sent at least one arg */
314 int sig_unused UNUSED;
315 {
316 #ifndef NO_SIGNAL
317     (void) signal(SIGINT, SIG_IGN);
318 #endif
319     if (flags.ignintr) {
320 #ifndef NO_SIGNAL
321         (void) signal(SIGINT, (SIG_RET_TYPE) done1);
322 #endif
323         clear_nhwindow(WIN_MESSAGE);
324         curs_on_u();
325         wait_synch();
326         if (multi > 0)
327             nomul(0);
328     } else {
329         (void) done2();
330     }
331 }
332
333 /* "#quit" command or keyboard interrupt */
334 int
335 done2()
336 {
337 /*JP
338     if (!paranoid_query(ParanoidQuit, "Really quit?")) {
339 */
340     if (!paranoid_query(ParanoidQuit, "\96{\93\96\82É\82â\82ß\82é\81H")) {
341 #ifndef NO_SIGNAL
342         (void) signal(SIGINT, (SIG_RET_TYPE) done1);
343 #endif
344         clear_nhwindow(WIN_MESSAGE);
345         curs_on_u();
346         wait_synch();
347         if (multi > 0)
348             nomul(0);
349         if (multi == 0) {
350             u.uinvulnerable = FALSE; /* avoid ctrl-C bug -dlc */
351             u.usleep = 0;
352         }
353         return 0;
354     }
355 #if (defined(UNIX) || defined(VMS) || defined(LATTICE))
356     if (wizard) {
357         int c;
358 #ifdef VMS
359         extern int debuggable; /* sys/vms/vmsmisc.c, vmsunix.c */
360
361         c = !debuggable ? 'n' : ynq("Enter debugger?");
362 #else
363 #ifdef LATTICE
364         c = ynq("Create SnapShot?");
365 #else
366         c = ynq("Dump core?");
367 #endif
368 #endif
369         if (c == 'y') {
370 #ifndef NO_SIGNAL
371             (void) signal(SIGINT, (SIG_RET_TYPE) done1);
372 #endif
373             exit_nhwindows((char *) 0);
374             NH_abort();
375         } else if (c == 'q')
376             done_stopprint++;
377     }
378 #endif
379 #ifndef LINT
380     done(QUIT);
381 #endif
382     return 0;
383 }
384
385 #ifndef NO_SIGNAL
386 /*ARGSUSED*/
387 STATIC_PTR void
388 done_intr(sig_unused) /* called as signal() handler, so sent at least 1 arg */
389 int sig_unused UNUSED;
390 {
391     done_stopprint++;
392     (void) signal(SIGINT, SIG_IGN);
393 #if defined(UNIX) || defined(VMS)
394     (void) signal(SIGQUIT, SIG_IGN);
395 #endif
396     return;
397 }
398
399 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
400 /* signal() handler */
401 static void
402 done_hangup(sig)
403 int sig;
404 {
405     program_state.done_hup++;
406     sethanguphandler((void FDECL((*), (int) )) SIG_IGN);
407     done_intr(sig);
408     return;
409 }
410 #endif
411 #endif /* NO_SIGNAL */
412
413 void
414 done_in_by(mtmp, how)
415 struct monst *mtmp;
416 int how;
417 {
418     char buf[BUFSZ];
419     struct permonst *mptr = mtmp->data,
420                     *champtr = ((mtmp->cham >= LOW_PM)
421                                    ? &mons[mtmp->cham]
422                                    : mptr);
423     boolean distorted = (boolean) (Hallucination && canspotmon(mtmp)),
424             mimicker = (mtmp->m_ap_type == M_AP_MONSTER),
425             imitator = (mptr != champtr || mimicker);
426
427 /*JP
428     You((how == STONING) ? "turn to stone..." : "die...");
429 */
430     You((how == STONING) ? "\90Î\82É\82È\82Á\82½\81D\81D\81D" : "\8e\80\82É\82Ü\82µ\82½\81D\81D\81D");
431     mark_synch(); /* flush buffered screen output */
432     buf[0] = '\0';
433     killer.format = KILLED_BY_AN;
434 #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 */
435     /* "killed by the high priest of Crom" is okay,
436        "killed by the high priest" alone isn't */
437     if ((mptr->geno & G_UNIQ) != 0 && !(imitator && !mimicker)
438         && !(mptr == &mons[PM_HIGH_PRIEST] && !mtmp->ispriest)) {
439         if (!type_is_pname(mptr))
440             Strcat(buf, "the ");
441         killer.format = KILLED_BY;
442     }
443     /* _the_ <invisible> <distorted> ghost of Dudley */
444     if (mptr == &mons[PM_GHOST] && has_mname(mtmp)) {
445         Strcat(buf, "the ");
446         killer.format = KILLED_BY;
447     }
448 #endif
449     if (mtmp->minvis)
450 /*JP
451         Strcat(buf, "invisible ");
452 */
453         Strcat(buf, "\93§\96¾\82È");
454     if (distorted)
455 /*JP
456         Strcat(buf, "hallucinogen-distorted ");
457 */
458         Strcat(buf, "\8c\8ao\82Å\98c\82ñ\82¾");
459
460     if (imitator) {
461         char shape[BUFSZ];
462         const char *realnm = champtr->mname, *fakenm = mptr->mname;
463         boolean alt = is_vampshifter(mtmp);
464
465         if (mimicker) {
466             /* realnm is already correct because champtr==mptr;
467                set up fake mptr for type_is_pname/the_unique_pm */
468             mptr = &mons[mtmp->mappearance];
469             fakenm = mptr->mname;
470 #if 0 /*JP*/
471         } else if (alt && strstri(realnm, "vampire")
472                    && !strcmp(fakenm, "vampire bat")) {
473             /* special case: use "vampire in bat form" in preference
474                to redundant looking "vampire in vampire bat form" */
475             fakenm = "bat";
476 #else
477         } else if (alt && strstri(realnm, "\8bz\8c\8c\8bS")
478                    && !strcmp(fakenm, "\8bz\8c\8c\82±\82¤\82à\82è")) {
479             /* \81u\8bz\8c\8c\82±\82¤\82à\82è\82Ì\8ep\82Ì\8bz\8c\8c\8bS\81v\82Í\8fç\92·\82È\82Ì\82Å
480                \81u\82±\82¤\82à\82è\82Ì\8ep\82Ì\8bz\8c\8c\8bS\81v\82Ì\8c`\82É\82·\82é */
481             fakenm = "\82±\82¤\82à\82è";
482 #endif
483         }
484 #if 0 /*JP*/
485         /* for the alternate format, always suppress any article;
486            pname and the_unique should also have s_suffix() applied,
487            but vampires don't take on any shapes which warrant that */
488         if (alt || type_is_pname(mptr)) /* no article */
489             Strcpy(shape, fakenm);
490         else if (the_unique_pm(mptr)) /* "the"; don't use the() here */
491             Sprintf(shape, "the %s", fakenm);
492         else /* "a"/"an" */
493             Strcpy(shape, an(fakenm));
494 #else /*JP:\93ú\96{\8cê\82Å\82Í\83V\83\93\83v\83\8b*/
495         Strcpy(shape, fakenm);
496 #endif
497         /* omit "called" to avoid excessive verbosity */
498 #if 0 /*JP*/
499         Sprintf(eos(buf),
500                 alt ? "%s in %s form"
501                     : mimicker ? "%s disguised as %s"
502                                : "%s imitating %s",
503                 realnm, shape);
504 #else
505         Sprintf(eos(buf),
506                 alt ? "%s\82Ì\8ep\82Ì%s"
507                     : mimicker ? "%s\82Ì\82Ó\82è\82ð\82µ\82Ä\82¢\82é%s"
508                                : "%s\82Ì\82Ü\82Ë\82ð\82µ\82Ä\82¢\82é%s",
509                 shape, realnm);
510 #endif
511         mptr = mtmp->data; /* reset for mimicker case */
512     } else if (mptr == &mons[PM_GHOST]) {
513 #if 0 /*JP*/
514         Strcat(buf, "ghost");
515         if (has_mname(mtmp))
516             Sprintf(eos(buf), " of %s", MNAME(mtmp));
517 #else
518         if (has_mname(mtmp))
519             Sprintf(eos(buf), "%s\82Ì\97H\97ì", MNAME(mtmp));
520         else
521             Strcat(buf, "\97H\97ì");
522 #endif
523     } else if (mtmp->isshk) {
524 #if 0 /*JP*/
525         const char *shknm = shkname(mtmp),
526                    *honorific = shkname_is_pname(mtmp) ? ""
527                                    : mtmp->female ? "Ms. " : "Mr. ";
528
529         Sprintf(eos(buf), "%s%s, the shopkeeper", honorific, shknm);
530 #else
531         Sprintf(eos(buf), "%s\82Æ\82¢\82¤\96¼\82Ì\93X\8eå", shkname(mtmp));
532 #endif
533         killer.format = KILLED_BY;
534     } else if (mtmp->ispriest || mtmp->isminion) {
535         /* m_monnam() suppresses "the" prefix plus "invisible", and
536            it overrides the effect of Hallucination on priestname() */
537         Strcat(buf, m_monnam(mtmp));
538     } else {
539 #if 0 /*JP*/
540         Strcat(buf, mptr->mname);
541         if (has_mname(mtmp))
542             Sprintf(eos(buf), " called %s", MNAME(mtmp));
543 #else
544         Strcat(buf, mptr->mname);
545 #endif
546     }
547
548     Strcpy(killer.name, buf);
549     if (mptr->mlet == S_WRAITH)
550         u.ugrave_arise = PM_WRAITH;
551     else if (mptr->mlet == S_MUMMY && urace.mummynum != NON_PM)
552         u.ugrave_arise = urace.mummynum;
553     else if (mptr->mlet == S_VAMPIRE && Race_if(PM_HUMAN))
554         u.ugrave_arise = PM_VAMPIRE;
555     else if (mptr == &mons[PM_GHOUL])
556         u.ugrave_arise = PM_GHOUL;
557     /* this could happen if a high-end vampire kills the hero
558        when ordinary vampires are genocided; ditto for wraiths */
559     if (u.ugrave_arise >= LOW_PM
560         && (mvitals[u.ugrave_arise].mvflags & G_GENOD))
561         u.ugrave_arise = NON_PM;
562
563 #if 1 /*JP*/
564     if (how == STONING){
565         /*JP
566               topten.c \82Ì killed_by_prefix \82ð\8eQ\8fÆ\82Ì\82±\82Æ\81B
567               STONING \82Ì\8fê\8d\87\82Í "\90Î\89»\82µ\82½" \82ª\95â\82í\82ê\82é\81B
568          */
569         Strcat(buf, "\82Ì\8dU\8c\82\82Å");
570     }
571     if (how == DIED){
572         /*JP
573               DIED \82Ì\8fê\8d\87\82Í\92Ê\8fí "\8e\80\82ñ\82¾" \82ª\95â\82í\82ê\82é\82ª\81A
574               \89ö\95¨\82É\82æ\82é\8fê\8d\87\82Í "\82É\8eE\82³\82ê\82½" \82ð\95â\82¤\81B
575          */
576         killer.format = KILLED_SUFFIX;
577         done(DIED);
578     }
579 #endif
580     done(how);
581     return;
582 }
583
584 #if defined(WIN32) && !defined(SYSCF)
585 #define NOTIFY_NETHACK_BUGS
586 #endif
587
588 /*VARARGS1*/
589 void panic
590 VA_DECL(const char *, str)
591 {
592     VA_START(str);
593     VA_INIT(str, char *);
594
595     if (program_state.panicking++)
596         NH_abort(); /* avoid loops - this should never happen*/
597
598     if (iflags.window_inited) {
599         raw_print("\r\nOops...");
600         wait_synch(); /* make sure all pending output gets flushed */
601         exit_nhwindows((char *) 0);
602         iflags.window_inited = 0; /* they're gone; force raw_print()ing */
603     }
604
605     raw_print(program_state.gameover
606 /*JP
607                   ? "Postgame wrapup disrupted."
608 */
609                   ? "\83Q\81[\83\80\8fI\97¹\8e\9e\82Ì\8f\88\97\9d\82ª\95ö\89ó\82µ\82½\81D"
610                   : !program_state.something_worth_saving
611 /*JP
612                         ? "Program initialization has failed."
613 */
614                         ? "\83v\83\8d\83O\83\89\83\80\82Ì\8f\89\8aú\89»\82É\8e¸\94s\82µ\82½\81D"
615 /*JP
616                         : "Suddenly, the dungeon collapses.");
617 */
618                         : "\93Ë\91R\96À\8b{\82ª\95ö\82ê\82½\81D");
619 #ifndef MICRO
620 #if defined(NOTIFY_NETHACK_BUGS)
621     if (!wizard)
622         raw_printf("Report the following error to \"%s\" or at \"%s\".",
623                    DEVTEAM_EMAIL, DEVTEAM_URL);
624     else if (program_state.something_worth_saving)
625         raw_print("\nError save file being written.\n");
626 #else
627     if (!wizard) {
628 #if 0 /*JP*/
629         const char *maybe_rebuild = !program_state.something_worth_saving
630                                      ? "."
631                                      : "\nand it may be possible to rebuild.";
632 #else
633         const char *maybe_rebuild = !program_state.something_worth_saving
634                                      ? "\81D"
635                                      : "\n\95\9c\8b\8c\82Å\82«\82é\89Â\94\\90«\82ª\82 \82è\82Ü\82·\81D";
636 #endif
637
638         if (sysopt.support)
639             raw_printf("To report this error, %s%s", sysopt.support,
640                        maybe_rebuild);
641         else if (sysopt.fmtd_wizard_list) /* formatted SYSCF WIZARDS */
642             raw_printf("To report this error, contact %s%s",
643                        sysopt.fmtd_wizard_list, maybe_rebuild);
644         else
645 #if 0 /*JP*/
646             raw_printf("Report error to \"%s\"%s", WIZARD_NAME,
647                        maybe_rebuild);
648 #else
649             raw_printf("\"%s\"\82É\83G\83\89\81[\82ð\95ñ\8d\90\82µ\82Ä\82­\82¾\82³\82¢\81D%s", WIZARD_NAME,
650                        maybe_rebuild);
651 #endif
652     }
653 #endif
654     /* XXX can we move this above the prints?  Then we'd be able to
655      * suppress "it may be possible to rebuild" based on dosave0()
656      * or say it's NOT possible to rebuild. */
657     if (program_state.something_worth_saving) {
658         set_error_savefile();
659         if (dosave0()) {
660             /* os/win port specific recover instructions */
661             if (sysopt.recover)
662                 raw_printf("%s", sysopt.recover);
663         }
664     }
665 #endif
666     {
667         char buf[BUFSZ];
668
669         Vsprintf(buf, str, VA_ARGS);
670         raw_print(buf);
671         paniclog("panic", buf);
672     }
673 #ifdef WIN32
674     interject(INTERJECT_PANIC);
675 #endif
676 #if defined(UNIX) || defined(VMS) || defined(LATTICE) || defined(WIN32)
677     if (wizard)
678         NH_abort(); /* generate core dump */
679 #endif
680     VA_END();
681     really_done(PANICKED);
682 }
683
684 STATIC_OVL boolean
685 should_query_disclose_option(category, defquery)
686 int category;
687 char *defquery;
688 {
689     int idx;
690     char *dop;
691
692     *defquery = 'n';
693     if ((dop = index(disclosure_options, category)) != 0) {
694         idx = (int) (dop - disclosure_options);
695         if (idx < 0 || idx >= NUM_DISCLOSURE_OPTIONS) {
696             impossible(
697                    "should_query_disclose_option: bad disclosure index %d %c",
698                        idx, category);
699             *defquery = DISCLOSE_PROMPT_DEFAULT_YES;
700             return TRUE;
701         }
702         if (flags.end_disclose[idx] == DISCLOSE_YES_WITHOUT_PROMPT) {
703             *defquery = 'y';
704             return FALSE;
705         } else if (flags.end_disclose[idx] == DISCLOSE_NO_WITHOUT_PROMPT) {
706             *defquery = 'n';
707             return FALSE;
708         } else if (flags.end_disclose[idx] == DISCLOSE_PROMPT_DEFAULT_YES) {
709             *defquery = 'y';
710             return TRUE;
711         } else {
712             *defquery = 'n';
713             return TRUE;
714         }
715     }
716     impossible("should_query_disclose_option: bad category %c", category);
717     return TRUE;
718 }
719
720 STATIC_OVL void
721 disclose(how, taken)
722 int how;
723 boolean taken;
724 {
725     char c = '\0', defquery;
726     char qbuf[QBUFSZ];
727     boolean ask = FALSE;
728
729     if (invent && !done_stopprint) {
730         if (taken)
731 #if 0 /*JP*/
732             Sprintf(qbuf, "Do you want to see what you had when you %s?",
733                     (how == QUIT) ? "quit" : "died");
734 #else
735             Sprintf(qbuf,"%s\82Æ\82«\89½\82ð\8e\9d\82Á\82Ä\82¢\82½\82©\8c©\82Ü\82·\82©\81H",
736                     (how == QUIT) ? "\82â\82ß\82½" : "\8e\80\82ñ\82¾");
737 #endif
738         else
739 /*JP
740             Strcpy(qbuf, "Do you want your possessions identified?");
741 */
742             Strcpy(qbuf,"\8e\9d\82¿\95¨\82ð\8e¯\95Ê\82µ\82Ü\82·\82©\81H"); 
743
744         ask = should_query_disclose_option('i', &defquery);
745         c = ask ? yn_function(qbuf, ynqchars, defquery) : defquery;
746         if (c == 'y') {
747             struct obj *obj;
748
749             for (obj = invent; obj; obj = obj->nobj) {
750                 makeknown(obj->otyp);
751                 obj->known = obj->bknown = obj->dknown = obj->rknown = 1;
752                 if (Is_container(obj) || obj->otyp == STATUE)
753                     obj->cknown = obj->lknown = 1;
754             }
755             (void) display_inventory((char *) 0, TRUE);
756             container_contents(invent, TRUE, TRUE, FALSE);
757         }
758         if (c == 'q')
759             done_stopprint++;
760     }
761
762     if (!done_stopprint) {
763         ask = should_query_disclose_option('a', &defquery);
764 #if 0 /*JP*/
765         c = ask ? yn_function("Do you want to see your attributes?", ynqchars,
766                               defquery)
767                 : defquery;
768 #else
769         c = ask ? yn_function("\91®\90«\82ð\8c©\82Ü\82·\82©\81H", ynqchars,
770                               defquery)
771                 : defquery;
772 #endif
773         if (c == 'y')
774             enlightenment((BASICENLIGHTENMENT | MAGICENLIGHTENMENT),
775                           (how >= PANICKED) ? ENL_GAMEOVERALIVE
776                                             : ENL_GAMEOVERDEAD);
777         if (c == 'q')
778             done_stopprint++;
779     }
780
781     if (!done_stopprint) {
782         ask = should_query_disclose_option('v', &defquery);
783         list_vanquished(defquery, ask);
784     }
785
786     if (!done_stopprint) {
787         ask = should_query_disclose_option('g', &defquery);
788         list_genocided(defquery, ask);
789     }
790
791     if (!done_stopprint) {
792         ask = should_query_disclose_option('c', &defquery);
793 #if 0 /*JP*/
794         c = ask ? yn_function("Do you want to see your conduct?", ynqchars,
795                               defquery)
796                 : defquery;
797 #else
798         c = ask ? yn_function("\82Ç\82¤\82¢\82¤\8ds\93®\82ð\82Æ\82Á\82½\82©\8c©\82Ü\82·\82©\81H", ynqchars,
799                               defquery)
800                 : defquery;
801 #endif
802         if (c == 'y')
803             show_conduct((how >= PANICKED) ? 1 : 2);
804         if (c == 'q')
805             done_stopprint++;
806     }
807
808     if (!done_stopprint) {
809         ask = should_query_disclose_option('o', &defquery);
810 #if 0 /*JP*/
811         c = ask ? yn_function("Do you want to see the dungeon overview?",
812                               ynqchars, defquery)
813                 : defquery;
814 #else
815         c = ask ? yn_function("\96À\8b{\82Ì\8aT\97v\82ð\8c©\82Ü\82·\82©\81H",
816                               ynqchars, defquery)
817                 : defquery;
818 #endif
819         if (c == 'y')
820             show_overview((how >= PANICKED) ? 1 : 2, how);
821         if (c == 'q')
822             done_stopprint++;
823     }
824 }
825
826 /* try to get the player back in a viable state after being killed */
827 STATIC_OVL void
828 savelife(how)
829 int how;
830 {
831     int uhpmin = max(2 * u.ulevel, 10);
832
833     if (u.uhpmax < uhpmin)
834         u.uhpmax = uhpmin;
835     u.uhp = u.uhpmax;
836     u.uswldtim = 0;
837     if (u.uhunger < 500) {
838         u.uhunger = 500;
839         newuhs(FALSE);
840     }
841     /* cure impending doom of sickness hero won't have time to fix */
842     if ((Sick & TIMEOUT) == 1L) {
843         u.usick_type = 0;
844         set_itimeout(&Sick, 0L);
845     }
846     if (how == CHOKING)
847         init_uhunger();
848 /*JP
849     nomovemsg = "You survived that attempt on your life.";
850 */
851     nomovemsg = "\82 \82È\82½\82Í\90\82«\82È\82ª\82ç\82¦\82½\81D";
852     context.move = 0;
853     if (multi > 0)
854         multi = 0;
855     else
856         multi = -1;
857     if (u.utrap && u.utraptype == TT_LAVA)
858         u.utrap = 0;
859     context.botl = 1;
860     u.ugrave_arise = NON_PM;
861     HUnchanging = 0L;
862     curs_on_u();
863 }
864
865 /*
866  * Get valuables from the given list.  Revised code: the list always remains
867  * intact.
868  */
869 STATIC_OVL void
870 get_valuables(list)
871 struct obj *list; /* inventory or container contents */
872 {
873     register struct obj *obj;
874     register int i;
875
876     /* find amulets and gems, ignoring all artifacts */
877     for (obj = list; obj; obj = obj->nobj)
878         if (Has_contents(obj)) {
879             get_valuables(obj->cobj);
880         } else if (obj->oartifact) {
881             continue;
882         } else if (obj->oclass == AMULET_CLASS) {
883             i = obj->otyp - FIRST_AMULET;
884             if (!amulets[i].count) {
885                 amulets[i].count = obj->quan;
886                 amulets[i].typ = obj->otyp;
887             } else
888                 amulets[i].count += obj->quan; /* always adds one */
889         } else if (obj->oclass == GEM_CLASS && obj->otyp < LUCKSTONE) {
890             i = min(obj->otyp, LAST_GEM + 1) - FIRST_GEM;
891             if (!gems[i].count) {
892                 gems[i].count = obj->quan;
893                 gems[i].typ = obj->otyp;
894             } else
895                 gems[i].count += obj->quan;
896         }
897     return;
898 }
899
900 /*
901  *  Sort collected valuables, most frequent to least.  We could just
902  *  as easily use qsort, but we don't care about efficiency here.
903  */
904 STATIC_OVL void
905 sort_valuables(list, size)
906 struct valuable_data list[];
907 int size; /* max value is less than 20 */
908 {
909     register int i, j;
910     struct valuable_data ltmp;
911
912     /* move greater quantities to the front of the list */
913     for (i = 1; i < size; i++) {
914         if (list[i].count == 0)
915             continue;   /* empty slot */
916         ltmp = list[i]; /* structure copy */
917         for (j = i; j > 0; --j)
918             if (list[j - 1].count >= ltmp.count)
919                 break;
920             else {
921                 list[j] = list[j - 1];
922             }
923         list[j] = ltmp;
924     }
925     return;
926 }
927
928 #define CAT_CHECK 2
929
930 STATIC_OVL boolean
931 odds_and_ends(list, what)
932 struct obj *list;
933 int what;
934 {
935     struct obj *otmp;
936     for (otmp = list; otmp; otmp = otmp->nobj) {
937         switch (what) {
938         case CAT_CHECK: /* Schroedinger's Cat */
939             /* Ascending is deterministic */
940             if (SchroedingersBox(otmp))
941                 return rn2(2);
942             break;
943         }
944         if (Has_contents(otmp))
945             return odds_and_ends(otmp->cobj, what);
946     }
947     return FALSE;
948 }
949
950 /* called twice; first to calculate total, then to list relevant items */
951 STATIC_OVL void
952 artifact_score(list, counting, endwin)
953 struct obj *list;
954 boolean counting; /* true => add up points; false => display them */
955 winid endwin;
956 {
957     char pbuf[BUFSZ];
958     struct obj *otmp;
959     long value, points;
960     short dummy; /* object type returned by artifact_name() */
961
962     for (otmp = list; otmp; otmp = otmp->nobj) {
963         if (otmp->oartifact || otmp->otyp == BELL_OF_OPENING
964             || otmp->otyp == SPE_BOOK_OF_THE_DEAD
965             || otmp->otyp == CANDELABRUM_OF_INVOCATION) {
966             value = arti_cost(otmp); /* zorkmid value */
967             points = value * 5 / 2;  /* score value */
968             if (counting) {
969                 nowrap_add(u.urexp, points);
970             } else {
971                 makeknown(otmp->otyp);
972                 otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
973                 /* assumes artifacts don't have quan > 1 */
974 #if 0 /*JP*/
975                 Sprintf(pbuf, "%s%s (worth %ld %s and %ld points)",
976                         the_unique_obj(otmp) ? "The " : "",
977                         otmp->oartifact ? artifact_name(xname(otmp), &dummy)
978                                         : OBJ_NAME(objects[otmp->otyp]),
979                         value, currency(value), points);
980 #else
981                 Sprintf(pbuf, "%s(%ld%s\81C%ld\83|\83C\83\93\83g\82Ì\89¿\92l)\81C",
982                         otmp->oartifact ? artifact_name(xname(otmp), &dummy)
983                                         : OBJ_NAME(objects[otmp->otyp]),
984                         value, currency(value), points);
985 #endif
986                 putstr(endwin, 0, pbuf);
987             }
988         }
989         if (Has_contents(otmp))
990             artifact_score(otmp->cobj, counting, endwin);
991     }
992 }
993
994 /* Be careful not to call panic from here! */
995 void
996 done(how)
997 int how;
998 {
999     if (how == TRICKED) {
1000         if (killer.name[0]) {
1001             paniclog("trickery", killer.name);
1002             killer.name[0] = 0;
1003         }
1004         if (wizard) {
1005 /*JP
1006             You("are a very tricky wizard, it seems.");
1007 */
1008             You("\82Æ\82Ä\82à\88µ\82¢\82É\82­\82¢wizard\82Ì\82æ\82¤\82¾\81D");
1009             return;
1010         }
1011     }
1012
1013     if (how == ASCENDED || (!killer.name[0] && how == GENOCIDED))
1014         killer.format = NO_KILLER_PREFIX;
1015     /* Avoid killed by "a" burning or "a" starvation */
1016     if (!killer.name[0] && (how == STARVING || how == BURNING))
1017         killer.format = KILLED_BY;
1018     if (!killer.name[0] || how >= PANICKED)
1019 /*JP
1020         Strcpy(killer.name, deaths[how]);
1021 */
1022         Strcpy(killer.name, ends[how]);
1023
1024     if (how < PANICKED)
1025         u.umortality++;
1026     if (Lifesaved && (how <= GENOCIDED)) {
1027 /*JP
1028         pline("But wait...");
1029 */
1030         pline("\82¿\82å\82Á\82Æ\82Ü\82Á\82½\81D\81D\81D");
1031         makeknown(AMULET_OF_LIFE_SAVING);
1032 /*JP
1033         Your("medallion %s!", !Blind ? "begins to glow" : "feels warm");
1034 */
1035         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½");
1036         if (how == CHOKING)
1037 /*JP
1038             You("vomit ...");
1039 */
1040             You("\93f\82¢\82½\81D\81D\81D");
1041 /*JP
1042         You_feel("much better!");
1043 */
1044         You("\8bC\95ª\82ª\82æ\82­\82È\82Á\82½\81I");
1045 /*JP
1046         pline_The("medallion crumbles to dust!");
1047 */
1048         pline("\96\82\8f\9c\82¯\82Í\82±\82È\82²\82È\82É\82­\82¾\82¯\82½\81I");
1049         if (uamul)
1050             useup(uamul);
1051
1052         (void) adjattrib(A_CON, -1, TRUE);
1053         savelife(how);
1054         if (how == GENOCIDED) {
1055 /*JP
1056             pline("Unfortunately you are still genocided...");
1057 */
1058             pline("\8ec\94O\82È\82ª\82ç\81C\82 \82È\82½\82Í\8bs\8eE\82³\82ê\82½\82Ü\82Ü\82¾\81D\81D\81D");
1059         } else {
1060             killer.name[0] = 0;
1061             killer.format = 0;
1062             return;
1063         }
1064     }
1065     if ((wizard || discover) && (how <= GENOCIDED) &&
1066 /*JP
1067         !paranoid_query(ParanoidDie, "Die?")) {
1068 */
1069         !paranoid_query(ParanoidDie, "\8e\80\82ñ\82Å\82Ý\82é\81H")) {
1070 /*JP
1071         pline("OK, so you don't %s.", (how == CHOKING) ? "choke" : "die");
1072 */
1073         You("\8e\80\82È\82È\82©\82Á\82½\81D");
1074         savelife(how);
1075         killer.name[0] = 0;
1076         killer.format = 0;
1077         return;
1078     }
1079     really_done(how);
1080 }
1081
1082 /* separated from done() in order to specify the __noreturn__ attribute */
1083 STATIC_OVL void
1084 really_done(how)
1085 int how;
1086 {
1087     boolean taken;
1088     char pbuf[BUFSZ];
1089     winid endwin = WIN_ERR;
1090     boolean bones_ok, have_windows = iflags.window_inited;
1091     struct obj *corpse = (struct obj *) 0;
1092     time_t endtime;
1093     long umoney;
1094     long tmp;
1095
1096     /*
1097      *  The game is now over...
1098      */
1099     program_state.gameover = 1;
1100     /* in case of a subsequent panic(), there's no point trying to save */
1101     program_state.something_worth_saving = 0;
1102     /* render vision subsystem inoperative */
1103     iflags.vision_inited = 0;
1104
1105     /* might have been killed while using a disposable item, so make sure
1106        it's gone prior to inventory disclosure and creation of bones data */
1107     inven_inuse(TRUE);
1108     /* maybe not on object lists; if an active light source, would cause
1109        big trouble (`obj_is_local' panic) for savebones() -> savelev() */
1110     if (thrownobj && thrownobj->where == OBJ_FREE)
1111         dealloc_obj(thrownobj);
1112     if (kickedobj && kickedobj->where == OBJ_FREE)
1113         dealloc_obj(kickedobj);
1114
1115     /* remember time of death here instead of having bones, rip, and
1116        topten figure it out separately and possibly getting different
1117        time or even day if player is slow responding to --More-- */
1118     urealtime.finish_time = endtime = getnow();
1119     urealtime.realtime += (long) (endtime - urealtime.start_timing);
1120
1121     /* Sometimes you die on the first move.  Life's not fair.
1122      * On those rare occasions you get hosed immediately, go out
1123      * smiling... :-)  -3.
1124      */
1125     if (moves <= 1 && how < PANICKED) /* You die... --More-- */
1126 /*JP
1127         pline("Do not pass go.  Do not collect 200 %s.", currency(200L));
1128 */
1129         pline("\92\8d\88Ó\88ê\95b\81C\89ö\89ä\88ê\90\81C\8e\80\96S\88ê\95à\81D");
1130
1131     if (have_windows)
1132         wait_synch(); /* flush screen output */
1133 #ifndef NO_SIGNAL
1134     (void) signal(SIGINT, (SIG_RET_TYPE) done_intr);
1135 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
1136     (void) signal(SIGQUIT, (SIG_RET_TYPE) done_intr);
1137     sethanguphandler(done_hangup);
1138 #endif
1139 #endif /* NO_SIGNAL */
1140
1141     bones_ok = (how < GENOCIDED) && can_make_bones();
1142
1143     if (bones_ok && launch_in_progress())
1144         force_launch_placement();
1145
1146     /* maintain ugrave_arise even for !bones_ok */
1147     if (how == PANICKED)
1148         u.ugrave_arise = (NON_PM - 3); /* no corpse, no grave */
1149     else if (how == BURNING || how == DISSOLVED) /* corpse burns up too */
1150         u.ugrave_arise = (NON_PM - 2); /* leave no corpse */
1151     else if (how == STONING)
1152         u.ugrave_arise = (NON_PM - 1); /* statue instead of corpse */
1153     else if (how == TURNED_SLIME)
1154         u.ugrave_arise = PM_GREEN_SLIME;
1155
1156     /* if pets will contribute to score, populate mydogs list now
1157        (bones creation isn't a factor, but pline() messaging is) */
1158     if (how == ESCAPED || how == ASCENDED)
1159         keepdogs(TRUE);
1160
1161     if (how == QUIT) {
1162         killer.format = NO_KILLER_PREFIX;
1163         if (u.uhp < 1) {
1164             how = DIED;
1165             u.umortality++; /* skipped above when how==QUIT */
1166 /*JP
1167             Strcpy(killer.name, "quit while already on Charon's boat");
1168 */
1169             Strcpy(killer.name, "\8eO\93r\82Ì\90ì\82Ì\93n\82µ\91D\82É\8fæ\82Á\82Ä\82¢\82é\8aÔ\82É\94²\82¯\82½");
1170         }
1171     }
1172     if (how == ESCAPED || how == PANICKED)
1173         killer.format = NO_KILLER_PREFIX;
1174
1175     if (how != PANICKED) {
1176         /* these affect score and/or bones, but avoid them during panic */
1177         taken = paybill((how == ESCAPED) ? -1 : (how != QUIT));
1178         paygd();
1179         clearpriests();
1180     } else
1181         taken = FALSE; /* lint; assert( !bones_ok ); */
1182
1183     clearlocks();
1184
1185     if (have_windows)
1186         display_nhwindow(WIN_MESSAGE, FALSE);
1187
1188     if (strcmp(flags.end_disclose, "none") && how != PANICKED)
1189         disclose(how, taken);
1190
1191     /* finish_paybill should be called after disclosure but before bones */
1192     if (bones_ok && taken)
1193         finish_paybill();
1194
1195     /* grave creation should be after disclosure so it doesn't have
1196        this grave in the current level's features for #overview */
1197     if (bones_ok && u.ugrave_arise == NON_PM
1198         && !(mvitals[u.umonnum].mvflags & G_NOCORPSE)) {
1199         int mnum = u.umonnum;
1200
1201         if (!Upolyd) {
1202             /* Base corpse on race when not poly'd since original
1203              * u.umonnum is based on role, and all role monsters
1204              * are human.
1205              */
1206             mnum = (flags.female && urace.femalenum != NON_PM)
1207                        ? urace.femalenum
1208                        : urace.malenum;
1209         }
1210         corpse = mk_named_object(CORPSE, &mons[mnum], u.ux, u.uy, plname);
1211 /*JP
1212         Sprintf(pbuf, "%s, ", plname);
1213 */
1214         Sprintf(pbuf, "%s\82Ì\95æ\81C", plname);
1215         formatkiller(eos(pbuf), sizeof pbuf - strlen(pbuf), how);
1216         make_grave(u.ux, u.uy, pbuf);
1217     }
1218     pbuf[0] = '\0'; /* clear grave text; also lint suppression */
1219
1220     /* calculate score, before creating bones [container gold] */
1221     {
1222         int deepest = deepest_lev_reached(FALSE);
1223
1224         umoney = money_cnt(invent);
1225         tmp = u.umoney0;
1226         umoney += hidden_gold(); /* accumulate gold from containers */
1227         tmp = umoney - tmp;      /* net gain */
1228
1229         if (tmp < 0L)
1230             tmp = 0L;
1231         if (how < PANICKED)
1232             tmp -= tmp / 10L;
1233         tmp += 50L * (long) (deepest - 1);
1234         if (deepest > 20)
1235             tmp += 1000L * (long) ((deepest > 30) ? 10 : deepest - 20);
1236         nowrap_add(u.urexp, tmp);
1237
1238         /* ascension gives a score bonus iff offering to original deity */
1239         if (how == ASCENDED && u.ualign.type == u.ualignbase[A_ORIGINAL]) {
1240             /* retaining original alignment: score *= 2;
1241                converting, then using helm-of-OA to switch back: *= 1.5 */
1242             tmp = (u.ualignbase[A_CURRENT] == u.ualignbase[A_ORIGINAL])
1243                       ? u.urexp
1244                       : (u.urexp / 2L);
1245             nowrap_add(u.urexp, tmp);
1246         }
1247     }
1248
1249     if (u.ugrave_arise >= LOW_PM && u.ugrave_arise != PM_GREEN_SLIME) {
1250         /* give this feedback even if bones aren't going to be created,
1251            so that its presence or absence doesn't tip off the player to
1252            new bones or their lack; it might be a lie if makemon fails */
1253 /*JP
1254         Your("body rises from the dead as %s...",
1255 */
1256         Your("\91Ì\82Í%s\82Æ\82µ\82Ä\8e\80\91Ì\82©\82ç\91h\82Á\82½\81D\81D\81D",
1257              an(mons[u.ugrave_arise].mname));
1258         display_nhwindow(WIN_MESSAGE, FALSE);
1259     }
1260
1261     if (bones_ok) {
1262 /*JP
1263         if (!wizard || paranoid_query(ParanoidBones, "Save bones?"))
1264 */
1265         if (!wizard || paranoid_query(ParanoidBones, "\8d\9c\82ð\82¤\82ß\82é\81H"))
1266             savebones(how, endtime, corpse);
1267         /* corpse may be invalid pointer now so
1268             ensure that it isn't used again */
1269         corpse = (struct obj *) 0;
1270     }
1271
1272     /* update gold for the rip output, which can't use hidden_gold()
1273        (containers will be gone by then if bones just got saved...) */
1274     done_money = umoney;
1275
1276     /* clean up unneeded windows */
1277     if (have_windows) {
1278         wait_synch();
1279         free_pickinv_cache(); /* extra persistent window if perm_invent */
1280         if (WIN_INVEN != WIN_ERR)
1281             destroy_nhwindow(WIN_INVEN),  WIN_INVEN = WIN_ERR;
1282         display_nhwindow(WIN_MESSAGE, TRUE);
1283         destroy_nhwindow(WIN_MAP),  WIN_MAP = WIN_ERR;
1284 #ifndef STATUS_VIA_WINDOWPORT
1285         destroy_nhwindow(WIN_STATUS),  WIN_STATUS = WIN_ERR;
1286 #endif
1287         destroy_nhwindow(WIN_MESSAGE),  WIN_MESSAGE = WIN_ERR;
1288
1289         if (!done_stopprint || flags.tombstone)
1290             endwin = create_nhwindow(NHW_TEXT);
1291
1292         if (how < GENOCIDED && flags.tombstone && endwin != WIN_ERR)
1293             outrip(endwin, how, endtime);
1294     } else
1295         done_stopprint = 1; /* just avoid any more output */
1296
1297     if (u.uhave.amulet) {
1298 /*JP
1299         Strcat(killer.name, " (with the Amulet)");
1300 */
1301         Strcat(killer.name, "\96\82\8f\9c\82¯\82ð\8eè\82É");
1302     } else if (how == ESCAPED) {
1303         if (Is_astralevel(&u.uz)) /* offered Amulet to wrong deity */
1304 /*JP
1305             Strcat(killer.name, " (in celestial disgrace)");
1306 */
1307             Strcat(killer.name, "\93V\8fã\82Å\92p\90J\82ð\8eó\82¯\92E\8fo\82µ\82½");
1308         else if (carrying(FAKE_AMULET_OF_YENDOR))
1309 /*JP
1310             Strcat(killer.name, " (with a fake Amulet)");
1311 */
1312             Strcat(killer.name, "\8bU\95¨\82Ì\96\82\8f\9c\82¯\82ð\92Í\82Ü\82³\82ê\92E\8fo\82µ\82½");
1313         /* don't bother counting to see whether it should be plural */
1314     }
1315
1316     if (!done_stopprint) {
1317 #if 0 /*JP*/
1318         Sprintf(pbuf, "%s %s the %s...", Goodbye(), plname,
1319                 (how != ASCENDED)
1320                  ? (const char *) ((flags.female && urole.name.f)
1321                                       ? urole.name.f
1322                                       : urole.name.m)
1323                  : (const char *) (flags.female ? "Demigoddess" : "Demigod"));
1324 #else
1325         Sprintf(pbuf, "%s%s\82Ì%s\81D\81D\81D", Goodbye(),
1326                 how != ASCENDED
1327                 ? (const char *) ((flags.female && urole.name.f)
1328                                       ? urole.name.f
1329                                       : urole.name.m)
1330                 : (const char *) (flags.female ? "\8f\97\90_" : "\90_"),
1331                 plname);
1332 #endif
1333         putstr(endwin, 0, pbuf);
1334         putstr(endwin, 0, "");
1335     }
1336
1337     if (how == ESCAPED || how == ASCENDED) {
1338         struct monst *mtmp;
1339         struct obj *otmp;
1340         register struct val_list *val;
1341         register int i;
1342
1343         for (val = valuables; val->list; val++)
1344             for (i = 0; i < val->size; i++) {
1345                 val->list[i].count = 0L;
1346             }
1347         get_valuables(invent);
1348
1349         /* add points for collected valuables */
1350         for (val = valuables; val->list; val++)
1351             for (i = 0; i < val->size; i++)
1352                 if (val->list[i].count != 0L) {
1353                     tmp = val->list[i].count
1354                           * (long) objects[val->list[i].typ].oc_cost;
1355                     nowrap_add(u.urexp, tmp);
1356                 }
1357
1358         /* count the points for artifacts */
1359         artifact_score(invent, TRUE, endwin);
1360
1361         viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */
1362         mtmp = mydogs;
1363         if (!done_stopprint)
1364 /*JP
1365             Strcpy(pbuf, "You");
1366 */
1367             Strcpy(pbuf, "\82 \82È\82½");
1368         if (!Schroedingers_cat) /* check here in case disclosure was off */
1369             Schroedingers_cat = odds_and_ends(invent, CAT_CHECK);
1370         if (Schroedingers_cat) {
1371             int mhp, m_lev = adj_lev(&mons[PM_HOUSECAT]);
1372             mhp = d(m_lev, 8);
1373             nowrap_add(u.urexp, mhp);
1374             if (!done_stopprint)
1375 /*JP
1376                 Strcat(eos(pbuf), " and Schroedinger's cat");
1377 */
1378                 Strcat(eos(pbuf), "\82Æ\83V\83\85\83\8c\83f\83B\83\93\83K\81[\82Ì\94L");
1379         }
1380         if (mtmp) {
1381             while (mtmp) {
1382                 if (!done_stopprint)
1383 /*JP
1384                     Sprintf(eos(pbuf), " and %s", mon_nam(mtmp));
1385 */
1386                     Sprintf(eos(pbuf), "\82Æ%s", mon_nam(mtmp));
1387                 if (mtmp->mtame)
1388                     nowrap_add(u.urexp, mtmp->mhp);
1389                 mtmp = mtmp->nmon;
1390             }
1391 #if 1 /*JP*/
1392             if (!done_stopprint)
1393                 Strcat(pbuf, "\82Í");
1394 #endif
1395             if (!done_stopprint)
1396                 putstr(endwin, 0, pbuf);
1397             pbuf[0] = '\0';
1398         } else {
1399             if (!done_stopprint)
1400 /*JP
1401                 Strcat(pbuf, " ");
1402 */
1403                 Strcat(pbuf, "\82Í");
1404         }
1405         if (!done_stopprint) {
1406 #if 0 /*JP*/
1407             Sprintf(eos(pbuf), "%s with %ld point%s,",
1408                     how == ASCENDED ? "went to your reward"
1409                                     : "escaped from the dungeon",
1410                     u.urexp, plur(u.urexp));
1411 #else
1412             Sprintf(eos(pbuf), "%ld\83|\83C\83\93\83g\83}\81[\83N\82µ%s\81D",
1413                     u.urexp,
1414                     how==ASCENDED ? "\8f¸\93V\82µ\82½" : "\96À\8b{\82©\82ç\92E\8fo\82µ\82½");
1415 #endif
1416             putstr(endwin, 0, pbuf);
1417         }
1418
1419         if (!done_stopprint)
1420             artifact_score(invent, FALSE, endwin); /* list artifacts */
1421
1422         /* list valuables here */
1423         for (val = valuables; val->list; val++) {
1424             sort_valuables(val->list, val->size);
1425             for (i = 0; i < val->size && !done_stopprint; i++) {
1426                 int typ = val->list[i].typ;
1427                 long count = val->list[i].count;
1428
1429                 if (count == 0L)
1430                     continue;
1431                 if (objects[typ].oc_class != GEM_CLASS || typ <= LAST_GEM) {
1432                     otmp = mksobj(typ, FALSE, FALSE);
1433                     makeknown(otmp->otyp);
1434                     otmp->known = 1;  /* for fake amulets */
1435                     otmp->dknown = 1; /* seen it (blindness fix) */
1436                     if (has_oname(otmp))
1437                         free_oname(otmp);
1438                     otmp->quan = count;
1439 #if 0 /*JP*/
1440                     Sprintf(pbuf, "%8ld %s (worth %ld %s),", count,
1441                             xname(otmp), count * (long) objects[typ].oc_cost,
1442                             currency(2L));
1443 #else
1444                     Sprintf(pbuf, "%ld\8cÂ\82Ì%s(%ld%s\82Ì\89¿\92l)\81C", count,
1445                             xname(otmp), count * (long) objects[typ].oc_cost,
1446                             currency(2L));
1447 #endif
1448                     obfree(otmp, (struct obj *) 0);
1449                 } else {
1450 #if 0 /*JP*/
1451                     Sprintf(pbuf, "%8ld worthless piece%s of colored glass,",
1452                             count, plur(count));
1453 #else
1454                     Sprintf(pbuf, "%ld\8cÂ\82Ì\89¿\92l\82Ì\82È\82¢\90F\82Â\82«\83K\83\89\83X\81C",
1455                             count);
1456 #endif
1457                 }
1458                 putstr(endwin, 0, pbuf);
1459             }
1460         }
1461
1462     } else if (!done_stopprint) {
1463         /* did not escape or ascend */
1464         if (u.uz.dnum == 0 && u.uz.dlevel <= 0) {
1465             /* level teleported out of the dungeon; `how' is DIED,
1466                due to falling or to "arriving at heaven prematurely" */
1467 #if 0 /*JP*/
1468             Sprintf(pbuf, "You %s beyond the confines of the dungeon",
1469                     (u.uz.dlevel < 0) ? "passed away" : ends[how]);
1470 #else
1471             Sprintf(pbuf, "\96À\8b{\82Ì\97Ì\88æ\82ð\89z\82¦%s\81D",
1472                     (u.uz.dlevel < 0) ? "\8fÁ\82¦\82³\82Á\82½" : ends[how]);
1473 #endif
1474         } else {
1475             /* more conventional demise */
1476             const char *where = dungeons[u.uz.dnum].dname;
1477
1478             if (Is_astralevel(&u.uz))
1479 /*JP
1480                 where = "The Astral Plane";
1481 */
1482                 where = "\90¸\97ì\8aE\82É\82Ä";
1483 /*JP
1484             Sprintf(pbuf, "You %s in %s", ends[how], where);
1485 */
1486             Sprintf(pbuf, "\82 \82È\82½\82Í%s", where);
1487             if (!In_endgame(&u.uz) && !Is_knox(&u.uz))
1488 #if 0 /*JP*/
1489                 Sprintf(eos(pbuf), " on dungeon level %d",
1490                         In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz));
1491 #else
1492                 Sprintf(eos(pbuf), "\82Ì\92n\89º%d\8aK\82Å",
1493                         In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz));
1494 #endif
1495         }
1496
1497 /*JP
1498         Sprintf(eos(pbuf), " with %ld point%s,", u.urexp, plur(u.urexp));
1499 */
1500         Sprintf(eos(pbuf), " %ld\83|\83C\83\93\83g\82ð\83}\81[\83N\82µ\81C", u.urexp);
1501         putstr(endwin, 0, pbuf);
1502     }
1503
1504     if (!done_stopprint) {
1505 #if 0 /*JP*/
1506         Sprintf(pbuf, "and %ld piece%s of gold, after %ld move%s.", umoney,
1507                 plur(umoney), moves, plur(moves));
1508 #else
1509         Sprintf(pbuf, "%ld\96\87\82Ì\8bà\89Ý\82ð\8e\9d\82Á\82Ä\81C%ld\95à\93®\82¢\82½\81D",
1510                 umoney, moves);
1511 #endif
1512         putstr(endwin, 0, pbuf);
1513     }
1514     if (!done_stopprint) {
1515 #if 0 /*JP*/
1516         Sprintf(pbuf,
1517             "You were level %d with a maximum of %d hit point%s when you %s.",
1518                 u.ulevel, u.uhpmax, plur(u.uhpmax), ends[how]);
1519 #else
1520         Sprintf(pbuf,
1521                 "%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",
1522                 ends[how],u.ulevel, u.uhpmax);
1523 #endif
1524         putstr(endwin, 0, pbuf);
1525         putstr(endwin, 0, "");
1526     }
1527     if (!done_stopprint)
1528         display_nhwindow(endwin, TRUE);
1529     if (endwin != WIN_ERR)
1530         destroy_nhwindow(endwin);
1531
1532     /* "So when I die, the first thing I will see in Heaven is a
1533      * score list?" */
1534     if (have_windows && !iflags.toptenwin)
1535         exit_nhwindows((char *) 0), have_windows = FALSE;
1536     topten(how, endtime);
1537     if (have_windows)
1538         exit_nhwindows((char *) 0);
1539
1540     if (done_stopprint) {
1541         raw_print("");
1542         raw_print("");
1543     }
1544     terminate(EXIT_SUCCESS);
1545 }
1546
1547 void
1548 container_contents(list, identified, all_containers, reportempty)
1549 struct obj *list;
1550 boolean identified, all_containers, reportempty;
1551 {
1552     register struct obj *box, *obj;
1553     struct obj **oarray;
1554     int i, n;
1555     char *invlet;
1556     char buf[BUFSZ];
1557     boolean cat, deadcat;
1558
1559     for (box = list; box; box = box->nobj) {
1560         if (Is_container(box) || box->otyp == STATUE) {
1561             box->cknown = 1; /* we're looking at the contents now */
1562             if (identified)
1563                 box->lknown = 1;
1564             cat = deadcat = FALSE;
1565             if (SchroedingersBox(box) && !Schroedingers_cat) {
1566                 /* Schroedinger's Cat? */
1567                 cat = odds_and_ends(box, CAT_CHECK);
1568                 if (cat)
1569                     Schroedingers_cat = TRUE;
1570                 else
1571                     deadcat = TRUE;
1572                 box->spe = 0;
1573             }
1574             if (box->otyp == BAG_OF_TRICKS) {
1575                 continue; /* wrong type of container */
1576             } else if (box->cobj) {
1577                 winid tmpwin = create_nhwindow(NHW_MENU);
1578
1579                 /* count the number of items */
1580                 for (n = 0, obj = box->cobj; obj; obj = obj->nobj)
1581                     n++;
1582                 /* Make a temporary array to store the objects sorted */
1583                 oarray = objarr_init(n);
1584
1585                 /* Add objects to the array */
1586                 i = 0;
1587                 invlet = flags.inv_order;
1588             nextclass:
1589                 for (obj = box->cobj; obj; obj = obj->nobj) {
1590                     if (!flags.sortpack || obj->oclass == *invlet) {
1591                         objarr_set(
1592                             obj, i++, oarray,
1593                             (flags.sortloot == 'f' || flags.sortloot == 'l'));
1594                     }
1595                 } /* for loop */
1596                 if (flags.sortpack) {
1597                     if (*++invlet)
1598                         goto nextclass;
1599                 }
1600
1601 /*JP
1602                 Sprintf(buf, "Contents of %s:", the(xname(box)));
1603 */
1604                 Sprintf(buf, "%s\82Ì\92\86\90g\81F", the(xname(box)));
1605                 putstr(tmpwin, 0, buf);
1606                 putstr(tmpwin, 0, "");
1607                 for (i = 0; i < n; i++) {
1608                     obj = oarray[i];
1609                     if (identified) {
1610                         makeknown(obj->otyp);
1611                         obj->known = obj->bknown = obj->dknown = obj->rknown =
1612                             1;
1613                         if (Is_container(obj) || obj->otyp == STATUE)
1614                             obj->cknown = obj->lknown = 1;
1615                     }
1616                     putstr(tmpwin, 0, doname(obj));
1617                 }
1618                 free(oarray);
1619                 if (cat)
1620 /*JP
1621                     putstr(tmpwin, 0, "Schroedinger's cat");
1622 */
1623                     putstr(tmpwin, 0, "\83V\83\85\83\8c\83f\83B\83\93\83K\81[\82Ì\94L");
1624                 else if (deadcat)
1625 /*JP
1626                     putstr(tmpwin, 0, "Schroedinger's dead cat");
1627 */
1628                     putstr(tmpwin, 0, "\83V\83\85\83\8c\83f\83B\83\93\83K\81[\82Ì\94L\82Ì\8e\80\91Ì");
1629                 display_nhwindow(tmpwin, TRUE);
1630                 destroy_nhwindow(tmpwin);
1631                 if (all_containers)
1632                     container_contents(box->cobj, identified, TRUE,
1633                                        reportempty);
1634             } else if (cat || deadcat) {
1635 #if 0 /*JP*/
1636                 pline("%s Schroedinger's %scat!", Tobjnam(box, "contain"),
1637                       deadcat ? "dead " : "");
1638 #else
1639                 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),
1640                       deadcat ? "\82Ì\8e\80\91Ì" : "");
1641 #endif
1642                 display_nhwindow(WIN_MESSAGE, FALSE);
1643             } else if (reportempty) {
1644 /*JP
1645                 pline("%s is empty.", upstart(thesimpleoname(box)));
1646 */
1647                 pline("%s\82Í\8bó\82Á\82Û\82¾\81D", xname(box));
1648                 display_nhwindow(WIN_MESSAGE, FALSE);
1649             }
1650         }
1651         if (!all_containers)
1652             break;
1653     }
1654 }
1655
1656 /* should be called with either EXIT_SUCCESS or EXIT_FAILURE */
1657 void
1658 terminate(status)
1659 int status;
1660 {
1661     program_state.in_moveloop = 0; /* won't be returning to normal play */
1662 #ifdef MAC
1663     getreturn("to exit");
1664 #endif
1665     /* don't bother to try to release memory if we're in panic mode, to
1666        avoid trouble in case that happens to be due to memory problems */
1667     if (!program_state.panicking) {
1668         freedynamicdata();
1669         dlb_cleanup();
1670     }
1671
1672 #ifdef VMS
1673     /*
1674      *  This is liable to draw a warning if compiled with gcc, but it's
1675      *  more important to flag panic() -> really_done() -> terminate()
1676      *  as __noreturn__ then to avoid the warning.
1677      */
1678     /* don't call exit() if already executing within an exit handler;
1679        that would cancel any other pending user-mode handlers */
1680     if (program_state.exiting)
1681         return;
1682 #endif
1683     program_state.exiting = 1;
1684 #if 1 /*JP*/
1685     jputchar('\0'); /* reset terminal */
1686 #endif
1687     nethack_exit(status);
1688 }
1689
1690 /* #vanquished command */
1691 int
1692 dovanquished()
1693 {
1694     list_vanquished('a', FALSE);
1695     return 0;
1696 }
1697
1698 STATIC_OVL void
1699 list_vanquished(defquery, ask)
1700 char defquery;
1701 boolean ask;
1702 {
1703     register int i, lev;
1704     int ntypes = 0, max_lev = 0, nkilled;
1705     long total_killed = 0L;
1706     char c;
1707     winid klwin;
1708     char buf[BUFSZ];
1709
1710     /* get totals first */
1711     for (i = LOW_PM; i < NUMMONS; i++) {
1712         if (mvitals[i].died)
1713             ntypes++;
1714         total_killed += (long) mvitals[i].died;
1715         if (mons[i].mlevel > max_lev)
1716             max_lev = mons[i].mlevel;
1717     }
1718
1719     /* vanquished creatures list;
1720      * includes all dead monsters, not just those killed by the player
1721      */
1722     if (ntypes != 0) {
1723 #if 0 /*JP*/
1724         c = ask ? yn_function(
1725                             "Do you want an account of creatures vanquished?",
1726                               ynqchars, defquery)
1727                 : defquery;
1728 #else
1729         c = ask ? yn_function(
1730                             "\93|\82µ\82½\93G\82Ì\88ê\97\97\82ð\8c©\82Ü\82·\82©\81H",
1731                               ynqchars, defquery)
1732                 : defquery;
1733 #endif
1734         if (c == 'q')
1735             done_stopprint++;
1736         if (c == 'y' || c == 'a') {
1737             klwin = create_nhwindow(NHW_MENU);
1738 /*JP
1739             putstr(klwin, 0, "Vanquished creatures:");
1740 */
1741             putstr(klwin, 0, "\93|\82µ\82½\93G\81F");
1742             putstr(klwin, 0, "");
1743
1744             /* countdown by monster "toughness" */
1745             for (lev = max_lev; lev >= 0; lev--)
1746                 for (i = LOW_PM; i < NUMMONS; i++)
1747                     if (mons[i].mlevel == lev
1748                         && (nkilled = mvitals[i].died) > 0) {
1749                         if ((mons[i].geno & G_UNIQ) && i != PM_HIGH_PRIEST) {
1750 #if 0 /*JP*/
1751                             Sprintf(buf, "%s%s",
1752                                     !type_is_pname(&mons[i]) ? "The " : "",
1753                                     mons[i].mname);
1754 #else
1755                             Sprintf(buf, "%s", mons[i].mname);
1756 #endif
1757                             if (nkilled > 1) {
1758 #if 0 /*JP*/
1759                                 switch (nkilled) {
1760                                 case 2:
1761                                     Sprintf(eos(buf), " (twice)");
1762                                     break;
1763                                 case 3:
1764                                     Sprintf(eos(buf), " (thrice)");
1765                                     break;
1766                                 default:
1767                                     Sprintf(eos(buf), " (%d times)", nkilled);
1768                                     break;
1769                                 }
1770 #else
1771                                 Sprintf(eos(buf)," (%d\89ñ)", nkilled);
1772 #endif
1773                             }
1774                         } else {
1775                             /* trolls or undead might have come back,
1776                                but we don't keep track of that */
1777                             if (nkilled == 1)
1778                                 Strcpy(buf, an(mons[i].mname));
1779                             else
1780 #if 0 /*JP*/
1781                                 Sprintf(buf, "%d %s", nkilled,
1782                                         makeplural(mons[i].mname));
1783 #else
1784                                 Sprintf(buf, "%d\91Ì\82Ì%s", nkilled,
1785                                         mons[i].mname);
1786 #endif
1787                         }
1788                         putstr(klwin, 0, buf);
1789                     }
1790             /*
1791              * if (Hallucination)
1792              *     putstr(klwin, 0, "and a partridge in a pear tree");
1793              */
1794             if (ntypes > 1) {
1795                 putstr(klwin, 0, "");
1796 /*JP
1797                 Sprintf(buf, "%ld creatures vanquished.", total_killed);
1798 */
1799                 Sprintf(buf, "%ld\95C\82Ì\93G\82ð\93|\82µ\82½\81D", total_killed);
1800                 putstr(klwin, 0, buf);
1801             }
1802             display_nhwindow(klwin, TRUE);
1803             destroy_nhwindow(klwin);
1804         }
1805     } else if (defquery == 'a') {
1806         /* #dovanquished rather than final disclosure, so pline() is ok */
1807 /*JP
1808         pline("No monsters have been vanquished.");
1809 */
1810         pline("\93|\82µ\82½\93G\82Í\82¢\82È\82©\82Á\82½\81D");
1811     }
1812 }
1813
1814 /* number of monster species which have been genocided */
1815 int
1816 num_genocides()
1817 {
1818     int i, n = 0;
1819
1820     for (i = LOW_PM; i < NUMMONS; ++i)
1821         if (mvitals[i].mvflags & G_GENOD)
1822             ++n;
1823
1824     return n;
1825 }
1826
1827 int
1828 num_extinct()
1829 {
1830     int i, n = 0;
1831
1832     for (i = LOW_PM; i < NUMMONS; ++i)
1833         if (!(mvitals[i].mvflags & G_GENOD) && (mvitals[i].mvflags & G_GONE)
1834             && !(mons[i].geno & G_UNIQ))
1835             ++n;
1836
1837     return n;
1838 }
1839
1840 STATIC_OVL void
1841 list_genocided(defquery, ask)
1842 char defquery;
1843 boolean ask;
1844 {
1845     register int i;
1846     int ngenocided, nextinct;
1847     char c;
1848     winid klwin;
1849     char buf[BUFSZ];
1850
1851     ngenocided = num_genocides();
1852     nextinct = num_extinct();
1853
1854     /* genocided or extinct species list */
1855     if (ngenocided != 0 || nextinct != 0) {
1856 #if 0 /*JP*/
1857         Sprintf(buf, "Do you want a list of %sspecies%s%s?",
1858                 (nextinct && !ngenocided) ? "extinct " : "",
1859                 (ngenocided) ? " genocided" : "",
1860                 (nextinct && ngenocided) ? " and extinct" : "");
1861 #else
1862         Sprintf(buf, "%s%s%s\82µ\82½\8eí\82Ì\88ê\97\97\82ð\8c©\82Ü\82·\82©\81H",
1863                 (nextinct && !ngenocided) ? "\90â\96Å" : "",
1864                 (ngenocided) ? "\8bs\8eE" : "",
1865                 (nextinct && ngenocided) ? "\82¨\82æ\82Ñ\90â\96Å" : "");
1866 #endif
1867         c = ask ? yn_function(buf, ynqchars, defquery) : defquery;
1868         if (c == 'q')
1869             done_stopprint++;
1870         if (c == 'y') {
1871             klwin = create_nhwindow(NHW_MENU);
1872 #if 0 /*JP*/
1873             Sprintf(buf, "%s%s species:",
1874                     (ngenocided) ? "Genocided" : "Extinct",
1875                     (nextinct && ngenocided) ? " or extinct" : "");
1876 #else
1877             Sprintf(buf, "%s%s\82µ\82½\8eí:",
1878                     (ngenocided) ? "\8bs\8eE" : "\90â\96Å",
1879                     (nextinct && ngenocided) ? "\82Ü\82½\82Í\90â\96Å" : "");
1880 #endif
1881             putstr(klwin, 0, buf);
1882             putstr(klwin, 0, "");
1883
1884             for (i = LOW_PM; i < NUMMONS; i++)
1885                 if (mvitals[i].mvflags & G_GONE && !(mons[i].geno & G_UNIQ)) {
1886                     if ((mons[i].geno & G_UNIQ) && i != PM_HIGH_PRIEST)
1887 #if 0 /*JP*/
1888                         Sprintf(buf, "%s%s",
1889                                 !type_is_pname(&mons[i]) ? "" : "the ",
1890                                 mons[i].mname);
1891 #else
1892                         Sprintf(buf, "%s", mons[i].mname);
1893 #endif
1894                     else
1895                         Strcpy(buf, makeplural(mons[i].mname));
1896                     if (!(mvitals[i].mvflags & G_GENOD))
1897 /*JP
1898                         Strcat(buf, " (extinct)");
1899 */
1900                         Strcat(buf, "(\90â\96Å)");
1901                     putstr(klwin, 0, buf);
1902                 }
1903
1904             putstr(klwin, 0, "");
1905             if (ngenocided > 0) {
1906 /*JP
1907                 Sprintf(buf, "%d species genocided.", ngenocided);
1908 */
1909                 Sprintf(buf, "%d\8eí\97Þ\82Ì\8eí\82ð\8bs\8eE\82µ\82½\81D", ngenocided);
1910                 putstr(klwin, 0, buf);
1911             }
1912             if (nextinct > 0) {
1913 /*JP
1914                 Sprintf(buf, "%d species extinct.", nextinct);
1915 */
1916                 Sprintf(buf, "%d\8eí\97Þ\82Ì\8eí\82ð\90â\96Å\82³\82¹\82½\81D", nextinct);
1917                 putstr(klwin, 0, buf);
1918             }
1919
1920             display_nhwindow(klwin, TRUE);
1921             destroy_nhwindow(klwin);
1922         }
1923     }
1924 }
1925
1926 /* set a delayed killer, ensure non-delayed killer is cleared out */
1927 void
1928 delayed_killer(id, format, killername)
1929 int id;
1930 int format;
1931 const char *killername;
1932 {
1933     struct kinfo *k = find_delayed_killer(id);
1934
1935     if (k == (struct kinfo *) 0) {
1936         /* no match, add a new delayed killer to the list */
1937         k = (struct kinfo *) alloc(sizeof(struct kinfo));
1938         k->id = id;
1939         k->next = killer.next;
1940         killer.next = k;
1941     }
1942
1943     k->format = format;
1944     Strcpy(k->name, killername ? killername : "");
1945     killer.name[0] = 0;
1946 }
1947
1948 struct kinfo *
1949 find_delayed_killer(id)
1950 int id;
1951 {
1952     struct kinfo *k;
1953
1954     for (k = killer.next; k != (struct kinfo *) 0; k = k->next) {
1955         if (k->id == id)
1956             break;
1957     }
1958     return k;
1959 }
1960
1961 void
1962 dealloc_killer(kptr)
1963 struct kinfo *kptr;
1964 {
1965     struct kinfo *prev = &killer, *k;
1966
1967     if (kptr == (struct kinfo *) 0)
1968         return;
1969     for (k = killer.next; k != (struct kinfo *) 0; k = k->next) {
1970         if (k == kptr)
1971             break;
1972         prev = k;
1973     }
1974
1975     if (k == (struct kinfo *) 0) {
1976         impossible("dealloc_killer not on list");
1977     } else {
1978         prev->next = k->next;
1979         free((genericptr_t) k);
1980     }
1981 }
1982
1983 void
1984 save_killers(fd, mode)
1985 int fd;
1986 int mode;
1987 {
1988     struct kinfo *kptr;
1989
1990     if (perform_bwrite(mode)) {
1991         for (kptr = &killer; kptr != (struct kinfo *) 0; kptr = kptr->next) {
1992             bwrite(fd, (genericptr_t) kptr, sizeof(struct kinfo));
1993         }
1994     }
1995     if (release_data(mode)) {
1996         while (killer.next) {
1997             kptr = killer.next->next;
1998             free((genericptr_t) killer.next);
1999             killer.next = kptr;
2000         }
2001     }
2002 }
2003
2004 void
2005 restore_killers(fd)
2006 int fd;
2007 {
2008     struct kinfo *kptr;
2009
2010     for (kptr = &killer; kptr != (struct kinfo *) 0; kptr = kptr->next) {
2011         mread(fd, (genericptr_t) kptr, sizeof(struct kinfo));
2012         if (kptr->next) {
2013             kptr->next = (struct kinfo *) alloc(sizeof(struct kinfo));
2014         }
2015     }
2016 }
2017
2018 static int
2019 wordcount(p)
2020 char *p;
2021 {
2022     int words = 0;
2023
2024     while (*p) {
2025         while (*p && isspace((uchar) *p))
2026             p++;
2027         if (*p)
2028             words++;
2029         while (*p && !isspace((uchar) *p))
2030             p++;
2031     }
2032     return words;
2033 }
2034
2035 static void
2036 bel_copy1(inp, out)
2037 char **inp, *out;
2038 {
2039     char *in = *inp;
2040
2041     out += strlen(out); /* eos() */
2042     while (*in && isspace((uchar) *in))
2043         in++;
2044     while (*in && !isspace((uchar) *in))
2045         *out++ = *in++;
2046     *out = '\0';
2047     *inp = in;
2048 }
2049
2050 char *
2051 build_english_list(in)
2052 char *in;
2053 {
2054     char *out, *p = in;
2055     int len = (int) strlen(p), words = wordcount(p);
2056
2057     /* +3: " or " - " "; +(words - 1): (N-1)*(", " - " ") */
2058     if (words > 1)
2059         len += 3 + (words - 1);
2060     out = (char *) alloc(len + 1);
2061     *out = '\0'; /* bel_copy1() appends */
2062
2063     switch (words) {
2064     case 0:
2065         impossible("no words in list");
2066         break;
2067     case 1:
2068         /* "single" */
2069         bel_copy1(&p, out);
2070         break;
2071     default:
2072         if (words == 2) {
2073             /* "first or second" */
2074             bel_copy1(&p, out);
2075             Strcat(out, " ");
2076         } else {
2077             /* "first, second, or third */
2078             do {
2079                 bel_copy1(&p, out);
2080                 Strcat(out, ", ");
2081             } while (--words > 1);
2082         }
2083         Strcat(out, "or ");
2084         bel_copy1(&p, out);
2085         break;
2086     }
2087     return out;
2088 }
2089
2090 /*end.c*/