OSDN Git Service

GCC says embedding a directive within macro arguments is not portable
[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 #if 0 /*JP*//*\93ú\96{\8cê\82Å\82Í\8eg\82í\82È\82¢*/
594 static const struct {
595     int why, unmulti;
596     const char *exclude, *include;
597 } death_fixups[] = {
598     /* "petrified by <foo>, while getting stoned" -- "while getting stoned"
599        prevented any last-second recovery, but it was not the cause of
600        "petrified by <foo>" */
601     { STONING, 1, "getting stoned", (char *) 0 },
602     /* "died of starvation, while fainted from lack of food" is accurate
603        but sounds a fairly silly (and doesn't actually appear unless you
604        splice together death and while-helpless from xlogfile) */
605     { STARVING, 0, "fainted from lack of food", "fainted" },
606 };
607
608 /* clear away while-helpless when the cause of death caused that
609    helplessness (ie, "petrified by <foo> while getting stoned") */
610 STATIC_DCL void
611 fixup_death(how)
612 int how;
613 {
614     int i;
615
616     if (multi_reason) {
617         for (i = 0; i < SIZE(death_fixups); ++i)
618             if (death_fixups[i].why == how
619                 && !strcmp(death_fixups[i].exclude, multi_reason)) {
620                 if (death_fixups[i].include) /* substitute alternate reason */
621                     multi_reason = death_fixups[i].include;
622                 else /* remove the helplessness reason */
623                     multi_reason = (char *) 0;
624                 if (death_fixups[i].unmulti) /* possibly hide helplessness */
625                     multi = 0L;
626                 break;
627             }
628     }
629 }
630 #endif
631
632 #if defined(WIN32) && !defined(SYSCF)
633 #define NOTIFY_NETHACK_BUGS
634 #endif
635
636 /*VARARGS1*/
637 void panic
638 VA_DECL(const char *, str)
639 {
640     VA_START(str);
641     VA_INIT(str, char *);
642
643     if (program_state.panicking++)
644         NH_abort(); /* avoid loops - this should never happen*/
645
646     if (iflags.window_inited) {
647         raw_print("\r\nOops...");
648         wait_synch(); /* make sure all pending output gets flushed */
649         exit_nhwindows((char *) 0);
650         iflags.window_inited = 0; /* they're gone; force raw_print()ing */
651     }
652
653     raw_print(program_state.gameover
654 /*JP
655                   ? "Postgame wrapup disrupted."
656 */
657                   ? "\83Q\81[\83\80\8fI\97¹\8e\9e\82Ì\8f\88\97\9d\82ª\95ö\89ó\82µ\82½\81D"
658                   : !program_state.something_worth_saving
659 /*JP
660                         ? "Program initialization has failed."
661 */
662                         ? "\83v\83\8d\83O\83\89\83\80\82Ì\8f\89\8aú\89»\82É\8e¸\94s\82µ\82½\81D"
663 /*JP
664                         : "Suddenly, the dungeon collapses.");
665 */
666                         : "\93Ë\91R\96À\8b{\82ª\95ö\82ê\82½\81D");
667 #ifndef MICRO
668 #if defined(NOTIFY_NETHACK_BUGS)
669     if (!wizard)
670         raw_printf("Report the following error to \"%s\" or at \"%s\".",
671                    DEVTEAM_EMAIL, DEVTEAM_URL);
672     else if (program_state.something_worth_saving)
673         raw_print("\nError save file being written.\n");
674 #else
675     if (!wizard) {
676 #if 0 /*JP*/
677         const char *maybe_rebuild = !program_state.something_worth_saving
678                                      ? "."
679                                      : "\nand it may be possible to rebuild.";
680 #else
681         const char *maybe_rebuild = !program_state.something_worth_saving
682                                      ? "\81D"
683                                      : "\n\95\9c\8b\8c\82Å\82«\82é\89Â\94\\90«\82ª\82 \82è\82Ü\82·\81D";
684 #endif
685
686         if (sysopt.support)
687             raw_printf("To report this error, %s%s", sysopt.support,
688                        maybe_rebuild);
689         else if (sysopt.fmtd_wizard_list) /* formatted SYSCF WIZARDS */
690             raw_printf("To report this error, contact %s%s",
691                        sysopt.fmtd_wizard_list, maybe_rebuild);
692         else
693 #if 0 /*JP*/
694             raw_printf("Report error to \"%s\"%s", WIZARD_NAME,
695                        maybe_rebuild);
696 #else
697             raw_printf("\"%s\"\82É\83G\83\89\81[\82ð\95ñ\8d\90\82µ\82Ä\82­\82¾\82³\82¢\81D%s", WIZARD_NAME,
698                        maybe_rebuild);
699 #endif
700     }
701 #endif
702     /* XXX can we move this above the prints?  Then we'd be able to
703      * suppress "it may be possible to rebuild" based on dosave0()
704      * or say it's NOT possible to rebuild. */
705     if (program_state.something_worth_saving) {
706         set_error_savefile();
707         if (dosave0()) {
708             /* os/win port specific recover instructions */
709             if (sysopt.recover)
710                 raw_printf("%s", sysopt.recover);
711         }
712     }
713 #endif
714     {
715         char buf[BUFSZ];
716
717         Vsprintf(buf, str, VA_ARGS);
718         raw_print(buf);
719         paniclog("panic", buf);
720     }
721 #ifdef WIN32
722     interject(INTERJECT_PANIC);
723 #endif
724 #if defined(UNIX) || defined(VMS) || defined(LATTICE) || defined(WIN32)
725     if (wizard)
726         NH_abort(); /* generate core dump */
727 #endif
728     VA_END();
729     really_done(PANICKED);
730 }
731
732 STATIC_OVL boolean
733 should_query_disclose_option(category, defquery)
734 int category;
735 char *defquery;
736 {
737     int idx;
738     char disclose, *dop;
739
740     *defquery = 'n';
741     if ((dop = index(disclosure_options, category)) != 0) {
742         idx = (int) (dop - disclosure_options);
743         if (idx < 0 || idx >= NUM_DISCLOSURE_OPTIONS) {
744             impossible(
745                    "should_query_disclose_option: bad disclosure index %d %c",
746                        idx, category);
747             *defquery = DISCLOSE_PROMPT_DEFAULT_YES;
748             return TRUE;
749         }
750         disclose = flags.end_disclose[idx];
751         if (disclose == DISCLOSE_YES_WITHOUT_PROMPT) {
752             *defquery = 'y';
753             return FALSE;
754         } else if (disclose == DISCLOSE_SPECIAL_WITHOUT_PROMPT) {
755             *defquery = 'a';
756             return FALSE;
757         } else if (disclose == DISCLOSE_NO_WITHOUT_PROMPT) {
758             *defquery = 'n';
759             return FALSE;
760         } else if (disclose == DISCLOSE_PROMPT_DEFAULT_YES) {
761             *defquery = 'y';
762             return TRUE;
763         } else if (disclose == DISCLOSE_PROMPT_DEFAULT_SPECIAL) {
764             *defquery = 'a';
765             return TRUE;
766         } else {
767             *defquery = 'n';
768             return TRUE;
769         }
770     }
771     impossible("should_query_disclose_option: bad category %c", category);
772     return TRUE;
773 }
774
775 #ifdef DUMPLOG
776 STATIC_OVL void
777 dump_plines()
778 {
779     int i, j;
780     char buf[BUFSZ], **strp;
781     extern char *saved_plines[];
782     extern unsigned saved_pline_index;
783
784     Strcpy(buf, " "); /* one space for indentation */
785     putstr(0, 0, "Latest messages:");
786     for (i = 0, j = (int) saved_pline_index; i < DUMPLOG_MSG_COUNT;
787          ++i, j = (j + 1) % DUMPLOG_MSG_COUNT) {
788         strp = &saved_plines[j];
789         if (*strp) {
790             copynchars(&buf[1], *strp, BUFSZ - 1 - 1);
791             putstr(0, 0, buf);
792 #ifdef FREE_ALL_MEMORY
793             free(*strp), *strp = 0;
794 #endif
795         }
796     }
797 }
798 #endif
799
800 /*ARGSUSED*/
801 STATIC_OVL void
802 dump_everything(how, when)
803 int how;
804 time_t when; /* date+time at end of game */
805 {
806 #ifdef DUMPLOG
807     char pbuf[BUFSZ], datetimebuf[24]; /* [24]: room for 64-bit bogus value */
808
809     dump_redirect(TRUE);
810     if (!iflags.in_dumplog)
811         return;
812
813     init_symbols(); /* revert to default symbol set */
814
815     /* one line version ID, which includes build date+time;
816        it's conceivable that the game started with a different
817        build date+time or even with an older nethack version,
818        but we only have access to the one it finished under */
819     putstr(0, 0, getversionstring(pbuf));
820     putstr(0, 0, "");
821
822     /* game start and end date+time to disambiguate version date+time */
823     Strcpy(datetimebuf, yyyymmddhhmmss(ubirthday));
824     Sprintf(pbuf, "Game began %4.4s-%2.2s-%2.2s %2.2s:%2.2s:%2.2s",
825             &datetimebuf[0], &datetimebuf[4], &datetimebuf[6],
826             &datetimebuf[8], &datetimebuf[10], &datetimebuf[12]);
827     Strcpy(datetimebuf, yyyymmddhhmmss(when));
828     Sprintf(eos(pbuf), ", ended %4.4s-%2.2s-%2.2s %2.2s:%2.2s:%2.2s.",
829             &datetimebuf[0], &datetimebuf[4], &datetimebuf[6],
830             &datetimebuf[8], &datetimebuf[10], &datetimebuf[12]);
831     putstr(0, 0, pbuf);
832     putstr(0, 0, "");
833
834     /* character name and basic role info */
835     Sprintf(pbuf, "%s, %s %s %s %s", plname,
836             aligns[1 - u.ualign.type].adj,
837             genders[flags.female].adj,
838             urace.adj,
839             (flags.female && urole.name.f) ? urole.name.f : urole.name.m);
840     putstr(0, 0, pbuf);
841     putstr(0, 0, "");
842
843     dump_map();
844     putstr(0, 0, do_statusline1());
845     putstr(0, 0, do_statusline2());
846     putstr(0, 0, "");
847
848     dump_plines();
849     putstr(0, 0, "");
850     putstr(0, 0, "Inventory:");
851     display_inventory((char *) 0, TRUE);
852     container_contents(invent, TRUE, TRUE, FALSE);
853     enlightenment((BASICENLIGHTENMENT | MAGICENLIGHTENMENT),
854                   (how >= PANICKED) ? ENL_GAMEOVERALIVE : ENL_GAMEOVERDEAD);
855     putstr(0, 0, "");
856     list_vanquished('d', FALSE); /* 'd' => 'y' */
857     putstr(0, 0, "");
858     list_genocided('d', FALSE); /* 'd' => 'y' */
859     putstr(0, 0, "");
860     show_conduct((how >= PANICKED) ? 1 : 2);
861     putstr(0, 0, "");
862     show_overview((how >= PANICKED) ? 1 : 2, how);
863     putstr(0, 0, "");
864     dump_redirect(FALSE);
865 #else
866     nhUse(how);
867     nhUse(when);
868 #endif
869 }
870
871 STATIC_OVL void
872 disclose(how, taken)
873 int how;
874 boolean taken;
875 {
876     char c = '\0', defquery;
877     char qbuf[QBUFSZ];
878     boolean ask = FALSE;
879
880     if (invent && !done_stopprint) {
881         if (taken)
882 #if 0 /*JP*/
883             Sprintf(qbuf, "Do you want to see what you had when you %s?",
884                     (how == QUIT) ? "quit" : "died");
885 #else
886             Sprintf(qbuf,"%s\82Æ\82«\89½\82ð\8e\9d\82Á\82Ä\82¢\82½\82©\8c©\82Ü\82·\82©\81H",
887                     (how == QUIT) ? "\82â\82ß\82½" : "\8e\80\82ñ\82¾");
888 #endif
889         else
890 /*JP
891             Strcpy(qbuf, "Do you want your possessions identified?");
892 */
893             Strcpy(qbuf,"\8e\9d\82¿\95¨\82ð\8e¯\95Ê\82µ\82Ü\82·\82©\81H"); 
894
895         ask = should_query_disclose_option('i', &defquery);
896         c = ask ? yn_function(qbuf, ynqchars, defquery) : defquery;
897         if (c == 'y') {
898             /* caller has already ID'd everything */
899             (void) display_inventory((char *) 0, TRUE);
900             container_contents(invent, TRUE, TRUE, FALSE);
901         }
902         if (c == 'q')
903             done_stopprint++;
904     }
905
906     if (!done_stopprint) {
907         ask = should_query_disclose_option('a', &defquery);
908 #if 0 /*JP*/
909         c = ask ? yn_function("Do you want to see your attributes?", ynqchars,
910                               defquery)
911                 : defquery;
912 #else
913         c = ask ? yn_function("\91®\90«\82ð\8c©\82Ü\82·\82©\81H", ynqchars,
914                               defquery)
915                 : defquery;
916 #endif
917         if (c == 'y')
918             enlightenment((BASICENLIGHTENMENT | MAGICENLIGHTENMENT),
919                           (how >= PANICKED) ? ENL_GAMEOVERALIVE
920                                             : ENL_GAMEOVERDEAD);
921         if (c == 'q')
922             done_stopprint++;
923     }
924
925     if (!done_stopprint) {
926         ask = should_query_disclose_option('v', &defquery);
927         list_vanquished(defquery, ask);
928     }
929
930     if (!done_stopprint) {
931         ask = should_query_disclose_option('g', &defquery);
932         list_genocided(defquery, ask);
933     }
934
935     if (!done_stopprint) {
936         ask = should_query_disclose_option('c', &defquery);
937 #if 0 /*JP*/
938         c = ask ? yn_function("Do you want to see your conduct?", ynqchars,
939                               defquery)
940                 : defquery;
941 #else
942         c = ask ? yn_function("\82Ç\82¤\82¢\82¤\8ds\93®\82ð\82Æ\82Á\82½\82©\8c©\82Ü\82·\82©\81H", ynqchars,
943                               defquery)
944                 : defquery;
945 #endif
946         if (c == 'y')
947             show_conduct((how >= PANICKED) ? 1 : 2);
948         if (c == 'q')
949             done_stopprint++;
950     }
951
952     if (!done_stopprint) {
953         ask = should_query_disclose_option('o', &defquery);
954 #if 0 /*JP*/
955         c = ask ? yn_function("Do you want to see the dungeon overview?",
956                               ynqchars, defquery)
957                 : defquery;
958 #else
959         c = ask ? yn_function("\96À\8b{\82Ì\8aT\97v\82ð\8c©\82Ü\82·\82©\81H",
960                               ynqchars, defquery)
961                 : defquery;
962 #endif
963         if (c == 'y')
964             show_overview((how >= PANICKED) ? 1 : 2, how);
965         if (c == 'q')
966             done_stopprint++;
967     }
968 }
969
970 /* try to get the player back in a viable state after being killed */
971 STATIC_OVL void
972 savelife(how)
973 int how;
974 {
975     int uhpmin = max(2 * u.ulevel, 10);
976
977     if (u.uhpmax < uhpmin)
978         u.uhpmax = uhpmin;
979     u.uhp = u.uhpmax;
980     u.uswldtim = 0;
981     if (u.uhunger < 500) {
982         u.uhunger = 500;
983         newuhs(FALSE);
984     }
985     /* cure impending doom of sickness hero won't have time to fix */
986     if ((Sick & TIMEOUT) == 1L) {
987         u.usick_type = 0;
988         set_itimeout(&Sick, 0L);
989     }
990     if (how == CHOKING)
991         init_uhunger();
992 /*JP
993     nomovemsg = "You survived that attempt on your life.";
994 */
995     nomovemsg = "\82 \82È\82½\82Í\90\82«\82È\82ª\82ç\82¦\82½\81D";
996     context.move = 0;
997     if (multi > 0)
998         multi = 0;
999     else
1000         multi = -1;
1001     if (u.utrap && u.utraptype == TT_LAVA)
1002         u.utrap = 0;
1003     context.botl = 1;
1004     u.ugrave_arise = NON_PM;
1005     HUnchanging = 0L;
1006     curs_on_u();
1007     if (!context.mon_moving)
1008         endmultishot(FALSE);
1009 }
1010
1011 /*
1012  * Get valuables from the given list.  Revised code: the list always remains
1013  * intact.
1014  */
1015 STATIC_OVL void
1016 get_valuables(list)
1017 struct obj *list; /* inventory or container contents */
1018 {
1019     register struct obj *obj;
1020     register int i;
1021
1022     /* find amulets and gems, ignoring all artifacts */
1023     for (obj = list; obj; obj = obj->nobj)
1024         if (Has_contents(obj)) {
1025             get_valuables(obj->cobj);
1026         } else if (obj->oartifact) {
1027             continue;
1028         } else if (obj->oclass == AMULET_CLASS) {
1029             i = obj->otyp - FIRST_AMULET;
1030             if (!amulets[i].count) {
1031                 amulets[i].count = obj->quan;
1032                 amulets[i].typ = obj->otyp;
1033             } else
1034                 amulets[i].count += obj->quan; /* always adds one */
1035         } else if (obj->oclass == GEM_CLASS && obj->otyp < LUCKSTONE) {
1036             i = min(obj->otyp, LAST_GEM + 1) - FIRST_GEM;
1037             if (!gems[i].count) {
1038                 gems[i].count = obj->quan;
1039                 gems[i].typ = obj->otyp;
1040             } else
1041                 gems[i].count += obj->quan;
1042         }
1043     return;
1044 }
1045
1046 /*
1047  *  Sort collected valuables, most frequent to least.  We could just
1048  *  as easily use qsort, but we don't care about efficiency here.
1049  */
1050 STATIC_OVL void
1051 sort_valuables(list, size)
1052 struct valuable_data list[];
1053 int size; /* max value is less than 20 */
1054 {
1055     register int i, j;
1056     struct valuable_data ltmp;
1057
1058     /* move greater quantities to the front of the list */
1059     for (i = 1; i < size; i++) {
1060         if (list[i].count == 0)
1061             continue;   /* empty slot */
1062         ltmp = list[i]; /* structure copy */
1063         for (j = i; j > 0; --j)
1064             if (list[j - 1].count >= ltmp.count)
1065                 break;
1066             else {
1067                 list[j] = list[j - 1];
1068             }
1069         list[j] = ltmp;
1070     }
1071     return;
1072 }
1073
1074 #define CAT_CHECK 2
1075
1076 STATIC_OVL boolean
1077 odds_and_ends(list, what)
1078 struct obj *list;
1079 int what;
1080 {
1081     struct obj *otmp;
1082     for (otmp = list; otmp; otmp = otmp->nobj) {
1083         switch (what) {
1084         case CAT_CHECK: /* Schroedinger's Cat */
1085             /* Ascending is deterministic */
1086             if (SchroedingersBox(otmp))
1087                 return rn2(2);
1088             break;
1089         }
1090         if (Has_contents(otmp))
1091             return odds_and_ends(otmp->cobj, what);
1092     }
1093     return FALSE;
1094 }
1095
1096 /* called twice; first to calculate total, then to list relevant items */
1097 STATIC_OVL void
1098 artifact_score(list, counting, endwin)
1099 struct obj *list;
1100 boolean counting; /* true => add up points; false => display them */
1101 winid endwin;
1102 {
1103     char pbuf[BUFSZ];
1104     struct obj *otmp;
1105     long value, points;
1106     short dummy; /* object type returned by artifact_name() */
1107
1108     for (otmp = list; otmp; otmp = otmp->nobj) {
1109         if (otmp->oartifact || otmp->otyp == BELL_OF_OPENING
1110             || otmp->otyp == SPE_BOOK_OF_THE_DEAD
1111             || otmp->otyp == CANDELABRUM_OF_INVOCATION) {
1112             value = arti_cost(otmp); /* zorkmid value */
1113             points = value * 5 / 2;  /* score value */
1114             if (counting) {
1115                 nowrap_add(u.urexp, points);
1116             } else {
1117                 makeknown(otmp->otyp);
1118                 otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
1119                 /* assumes artifacts don't have quan > 1 */
1120 #if 0 /*JP*/
1121                 Sprintf(pbuf, "%s%s (worth %ld %s and %ld points)",
1122                         the_unique_obj(otmp) ? "The " : "",
1123                         otmp->oartifact ? artifact_name(xname(otmp), &dummy)
1124                                         : OBJ_NAME(objects[otmp->otyp]),
1125                         value, currency(value), points);
1126 #else
1127                 Sprintf(pbuf, "%s(%ld%s\81C%ld\83|\83C\83\93\83g\82Ì\89¿\92l)\81C",
1128                         otmp->oartifact ? artifact_name(xname(otmp), &dummy)
1129                                         : OBJ_NAME(objects[otmp->otyp]),
1130                         value, currency(value), points);
1131 #endif
1132                 putstr(endwin, 0, pbuf);
1133             }
1134         }
1135         if (Has_contents(otmp))
1136             artifact_score(otmp->cobj, counting, endwin);
1137     }
1138 }
1139
1140 /* Be careful not to call panic from here! */
1141 void
1142 done(how)
1143 int how;
1144 {
1145     if (how == TRICKED) {
1146         if (killer.name[0]) {
1147             paniclog("trickery", killer.name);
1148             killer.name[0] = 0;
1149         }
1150         if (wizard) {
1151 /*JP
1152             You("are a very tricky wizard, it seems.");
1153 */
1154             You("\82Æ\82Ä\82à\88µ\82¢\82É\82­\82¢wizard\82Ì\82æ\82¤\82¾\81D");
1155             return;
1156         }
1157     }
1158     if (program_state.panicking
1159 #ifdef HANGUPHANDLING
1160         || program_state.done_hup
1161 #endif
1162         ) {
1163         /* skip status update if panicking or disconnected */
1164         context.botl = context.botlx = FALSE;
1165     } else {
1166         /* otherwise force full status update */
1167         context.botlx = TRUE;
1168         bot();
1169     }
1170
1171     if (how == ASCENDED || (!killer.name[0] && how == GENOCIDED))
1172         killer.format = NO_KILLER_PREFIX;
1173     /* Avoid killed by "a" burning or "a" starvation */
1174     if (!killer.name[0] && (how == STARVING || how == BURNING))
1175         killer.format = KILLED_BY;
1176     if (!killer.name[0] || how >= PANICKED)
1177 /*JP
1178         Strcpy(killer.name, deaths[how]);
1179 */
1180         Strcpy(killer.name, ends[how]);
1181
1182     if (how < PANICKED)
1183         u.umortality++;
1184     if (Lifesaved && (how <= GENOCIDED)) {
1185 /*JP
1186         pline("But wait...");
1187 */
1188         pline("\82¿\82å\82Á\82Æ\82Ü\82Á\82½\81D\81D\81D");
1189         makeknown(AMULET_OF_LIFE_SAVING);
1190 /*JP
1191         Your("medallion %s!", !Blind ? "begins to glow" : "feels warm");
1192 */
1193         Your("\96\82\8f\9c\82¯\82Í%s\81I", !Blind ? "\8bP\82«\82Í\82\82ß\82½" : "\92g\82©\82­\82È\82è\82Í\82\82ß\82½");
1194         if (how == CHOKING)
1195 /*JP
1196             You("vomit ...");
1197 */
1198             You("\93f\82¢\82½\81D\81D\81D");
1199 /*JP
1200         You_feel("much better!");
1201 */
1202         You("\8bC\95ª\82ª\82æ\82­\82È\82Á\82½\81I");
1203 /*JP
1204         pline_The("medallion crumbles to dust!");
1205 */
1206         pline("\96\82\8f\9c\82¯\82Í\82±\82È\82²\82È\82É\82­\82¾\82¯\82½\81I");
1207         if (uamul)
1208             useup(uamul);
1209
1210         (void) adjattrib(A_CON, -1, TRUE);
1211         savelife(how);
1212         if (how == GENOCIDED) {
1213 /*JP
1214             pline("Unfortunately you are still genocided...");
1215 */
1216             pline("\8ec\94O\82È\82ª\82ç\81C\82 \82È\82½\82Í\8bs\8eE\82³\82ê\82½\82Ü\82Ü\82¾\81D\81D\81D");
1217         } else {
1218             killer.name[0] = 0;
1219             killer.format = 0;
1220             return;
1221         }
1222     }
1223 #if 0 /*JP*/
1224     if ((wizard || discover) && (how <= GENOCIDED)
1225         && !paranoid_query(ParanoidDie, "Die?")) {
1226 #else
1227     if ((wizard || discover) && (how <= GENOCIDED)
1228         && !paranoid_query(ParanoidDie, "\8e\80\82ñ\82Å\82Ý\82é\81H")) {
1229 #endif
1230 /*JP
1231         pline("OK, so you don't %s.", (how == CHOKING) ? "choke" : "die");
1232 */
1233         You("\8e\80\82È\82È\82©\82Á\82½\81D");
1234         savelife(how);
1235         killer.name[0] = 0;
1236         killer.format = 0;
1237         return;
1238     }
1239     really_done(how);
1240 }
1241
1242 /* separated from done() in order to specify the __noreturn__ attribute */
1243 STATIC_OVL void
1244 really_done(how)
1245 int how;
1246 {
1247     boolean taken;
1248     char pbuf[BUFSZ];
1249     winid endwin = WIN_ERR;
1250     boolean bones_ok, have_windows = iflags.window_inited;
1251     struct obj *corpse = (struct obj *) 0;
1252     time_t endtime;
1253     long umoney;
1254     long tmp;
1255
1256     /*
1257      *  The game is now over...
1258      */
1259     program_state.gameover = 1;
1260     /* in case of a subsequent panic(), there's no point trying to save */
1261     program_state.something_worth_saving = 0;
1262     /* render vision subsystem inoperative */
1263     iflags.vision_inited = 0;
1264
1265     /* might have been killed while using a disposable item, so make sure
1266        it's gone prior to inventory disclosure and creation of bones data */
1267     inven_inuse(TRUE);
1268     /* maybe not on object lists; if an active light source, would cause
1269        big trouble (`obj_is_local' panic) for savebones() -> savelev() */
1270     if (thrownobj && thrownobj->where == OBJ_FREE)
1271         dealloc_obj(thrownobj);
1272     if (kickedobj && kickedobj->where == OBJ_FREE)
1273         dealloc_obj(kickedobj);
1274
1275     /* remember time of death here instead of having bones, rip, and
1276        topten figure it out separately and possibly getting different
1277        time or even day if player is slow responding to --More-- */
1278     urealtime.finish_time = endtime = getnow();
1279     urealtime.realtime += (long) (endtime - urealtime.start_timing);
1280
1281     dump_open_log(endtime);
1282     /* Sometimes you die on the first move.  Life's not fair.
1283      * On those rare occasions you get hosed immediately, go out
1284      * smiling... :-)  -3.
1285      */
1286     if (moves <= 1 && how < PANICKED) /* You die... --More-- */
1287 /*JP
1288         pline("Do not pass go.  Do not collect 200 %s.", currency(200L));
1289 */
1290         pline("\92\8d\88Ó\88ê\95b\81C\89ö\89ä\88ê\90\81C\8e\80\96S\88ê\95à\81D");
1291
1292     if (have_windows)
1293         wait_synch(); /* flush screen output */
1294 #ifndef NO_SIGNAL
1295     (void) signal(SIGINT, (SIG_RET_TYPE) done_intr);
1296 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
1297     (void) signal(SIGQUIT, (SIG_RET_TYPE) done_intr);
1298     sethanguphandler(done_hangup);
1299 #endif
1300 #endif /* NO_SIGNAL */
1301
1302     bones_ok = (how < GENOCIDED) && can_make_bones();
1303
1304     if (bones_ok && launch_in_progress())
1305         force_launch_placement();
1306
1307     /* maintain ugrave_arise even for !bones_ok */
1308     if (how == PANICKED)
1309         u.ugrave_arise = (NON_PM - 3); /* no corpse, no grave */
1310     else if (how == BURNING || how == DISSOLVED) /* corpse burns up too */
1311         u.ugrave_arise = (NON_PM - 2); /* leave no corpse */
1312     else if (how == STONING)
1313         u.ugrave_arise = (NON_PM - 1); /* statue instead of corpse */
1314     else if (how == TURNED_SLIME)
1315         u.ugrave_arise = PM_GREEN_SLIME;
1316
1317     if (how == QUIT) {
1318         killer.format = NO_KILLER_PREFIX;
1319         if (u.uhp < 1) {
1320             how = DIED;
1321             u.umortality++; /* skipped above when how==QUIT */
1322 /*JP
1323             Strcpy(killer.name, "quit while already on Charon's boat");
1324 */
1325             Strcpy(killer.name, "\8eO\93r\82Ì\90ì\82Ì\93n\82µ\91D\82É\8fæ\82Á\82Ä\82¢\82é\8aÔ\82É\94²\82¯\82½");
1326         }
1327     }
1328     if (how == ESCAPED || how == PANICKED)
1329         killer.format = NO_KILLER_PREFIX;
1330
1331 #if 0 /*JP*//*\93ú\96{\8cê\82Å\82Í\8eg\82í\82È\82¢*/
1332     fixup_death(how); /* actually, fixup multi_reason */
1333 #endif
1334
1335     if (how != PANICKED) {
1336         /* these affect score and/or bones, but avoid them during panic */
1337         taken = paybill((how == ESCAPED) ? -1 : (how != QUIT));
1338         paygd();
1339         clearpriests();
1340     } else
1341         taken = FALSE; /* lint; assert( !bones_ok ); */
1342
1343     clearlocks();
1344
1345     if (have_windows)
1346         display_nhwindow(WIN_MESSAGE, FALSE);
1347
1348     if (how != PANICKED) {
1349         struct obj *obj;
1350
1351         /*
1352          * This is needed for both inventory disclosure and dumplog.
1353          * Both are optional, so do it once here instead of duplicating
1354          * it in both of those places.
1355          */
1356         for (obj = invent; obj; obj = obj->nobj) {
1357             makeknown(obj->otyp);
1358             obj->known = obj->bknown = obj->dknown = obj->rknown = 1;
1359             if (Is_container(obj) || obj->otyp == STATUE)
1360                 obj->cknown = obj->lknown = 1;
1361         }
1362
1363         if (strcmp(flags.end_disclose, "none"))
1364             disclose(how, taken);
1365
1366         dump_everything(how, endtime);
1367     }
1368
1369     /* if pets will contribute to score, populate mydogs list now
1370        (bones creation isn't a factor, but pline() messaging is; used to
1371        be done ever sooner, but we need it to come after dump_everything()
1372        so that any accompanying pets are still on the map during dump) */
1373     if (how == ESCAPED || how == ASCENDED)
1374         keepdogs(TRUE);
1375
1376     /* finish_paybill should be called after disclosure but before bones */
1377     if (bones_ok && taken)
1378         finish_paybill();
1379
1380     /* grave creation should be after disclosure so it doesn't have
1381        this grave in the current level's features for #overview */
1382     if (bones_ok && u.ugrave_arise == NON_PM
1383         && !(mvitals[u.umonnum].mvflags & G_NOCORPSE)) {
1384         int mnum = u.umonnum;
1385
1386         if (!Upolyd) {
1387             /* Base corpse on race when not poly'd since original
1388              * u.umonnum is based on role, and all role monsters
1389              * are human.
1390              */
1391             mnum = (flags.female && urace.femalenum != NON_PM)
1392                        ? urace.femalenum
1393                        : urace.malenum;
1394         }
1395         corpse = mk_named_object(CORPSE, &mons[mnum], u.ux, u.uy, plname);
1396 /*JP
1397         Sprintf(pbuf, "%s, ", plname);
1398 */
1399         Sprintf(pbuf, "%s\82Ì\95æ\81C", plname);
1400         formatkiller(eos(pbuf), sizeof pbuf - strlen(pbuf), how, TRUE);
1401         make_grave(u.ux, u.uy, pbuf);
1402     }
1403     pbuf[0] = '\0'; /* clear grave text; also lint suppression */
1404
1405     /* calculate score, before creating bones [container gold] */
1406     {
1407         int deepest = deepest_lev_reached(FALSE);
1408
1409         umoney = money_cnt(invent);
1410         tmp = u.umoney0;
1411         umoney += hidden_gold(); /* accumulate gold from containers */
1412         tmp = umoney - tmp;      /* net gain */
1413
1414         if (tmp < 0L)
1415             tmp = 0L;
1416         if (how < PANICKED)
1417             tmp -= tmp / 10L;
1418         tmp += 50L * (long) (deepest - 1);
1419         if (deepest > 20)
1420             tmp += 1000L * (long) ((deepest > 30) ? 10 : deepest - 20);
1421         nowrap_add(u.urexp, tmp);
1422
1423         /* ascension gives a score bonus iff offering to original deity */
1424         if (how == ASCENDED && u.ualign.type == u.ualignbase[A_ORIGINAL]) {
1425             /* retaining original alignment: score *= 2;
1426                converting, then using helm-of-OA to switch back: *= 1.5 */
1427             tmp = (u.ualignbase[A_CURRENT] == u.ualignbase[A_ORIGINAL])
1428                       ? u.urexp
1429                       : (u.urexp / 2L);
1430             nowrap_add(u.urexp, tmp);
1431         }
1432     }
1433
1434     if (u.ugrave_arise >= LOW_PM && u.ugrave_arise != PM_GREEN_SLIME) {
1435         /* give this feedback even if bones aren't going to be created,
1436            so that its presence or absence doesn't tip off the player to
1437            new bones or their lack; it might be a lie if makemon fails */
1438 /*JP
1439         Your("body rises from the dead as %s...",
1440 */
1441         Your("\91Ì\82Í%s\82Æ\82µ\82Ä\8e\80\91Ì\82©\82ç\91h\82Á\82½\81D\81D\81D",
1442              an(mons[u.ugrave_arise].mname));
1443         display_nhwindow(WIN_MESSAGE, FALSE);
1444     }
1445
1446     if (bones_ok) {
1447 /*JP
1448         if (!wizard || paranoid_query(ParanoidBones, "Save bones?"))
1449 */
1450         if (!wizard || paranoid_query(ParanoidBones, "\8d\9c\82ð\82¤\82ß\82é\81H"))
1451             savebones(how, endtime, corpse);
1452         /* corpse may be invalid pointer now so
1453             ensure that it isn't used again */
1454         corpse = (struct obj *) 0;
1455     }
1456
1457     /* update gold for the rip output, which can't use hidden_gold()
1458        (containers will be gone by then if bones just got saved...) */
1459     done_money = umoney;
1460
1461     /* clean up unneeded windows */
1462     if (have_windows) {
1463         wait_synch();
1464         free_pickinv_cache(); /* extra persistent window if perm_invent */
1465         if (WIN_INVEN != WIN_ERR) {
1466             destroy_nhwindow(WIN_INVEN),  WIN_INVEN = WIN_ERR;
1467             /* precaution in case any late update_inventory() calls occur */
1468             flags.perm_invent = 0;
1469         }
1470         display_nhwindow(WIN_MESSAGE, TRUE);
1471         destroy_nhwindow(WIN_MAP),  WIN_MAP = WIN_ERR;
1472 #ifndef STATUS_HILITES
1473         destroy_nhwindow(WIN_STATUS),  WIN_STATUS = WIN_ERR;
1474 #endif
1475         destroy_nhwindow(WIN_MESSAGE),  WIN_MESSAGE = WIN_ERR;
1476
1477         if (!done_stopprint || flags.tombstone)
1478             endwin = create_nhwindow(NHW_TEXT);
1479
1480         if (how < GENOCIDED && flags.tombstone && endwin != WIN_ERR)
1481             outrip(endwin, how, endtime);
1482     } else
1483         done_stopprint = 1; /* just avoid any more output */
1484
1485 #ifdef DUMPLOG
1486     /* 'how' reasons beyond genocide shouldn't show tombstone;
1487        for normal end of game, genocide doesn't either */
1488     if (how <= GENOCIDED) {
1489         dump_redirect(TRUE);
1490         if (iflags.in_dumplog)
1491             genl_outrip(0, how, endtime);
1492         dump_redirect(FALSE);
1493     }
1494 #endif
1495     if (u.uhave.amulet) {
1496 /*JP
1497         Strcat(killer.name, " (with the Amulet)");
1498 */
1499         Strcat(killer.name, "\96\82\8f\9c\82¯\82ð\8eè\82É");
1500     } else if (how == ESCAPED) {
1501         if (Is_astralevel(&u.uz)) /* offered Amulet to wrong deity */
1502 /*JP
1503             Strcat(killer.name, " (in celestial disgrace)");
1504 */
1505             Strcat(killer.name, "\93V\8fã\82Å\92p\90J\82ð\8eó\82¯\92E\8fo\82µ\82½");
1506         else if (carrying(FAKE_AMULET_OF_YENDOR))
1507 /*JP
1508             Strcat(killer.name, " (with a fake Amulet)");
1509 */
1510             Strcat(killer.name, "\8bU\95¨\82Ì\96\82\8f\9c\82¯\82ð\92Í\82Ü\82³\82ê\92E\8fo\82µ\82½");
1511         /* don't bother counting to see whether it should be plural */
1512     }
1513
1514 #if 0 /*JP*/
1515     Sprintf(pbuf, "%s %s the %s...", Goodbye(), plname,
1516             (how != ASCENDED)
1517                 ? (const char *) ((flags.female && urole.name.f)
1518                     ? urole.name.f
1519                     : urole.name.m)
1520                 : (const char *) (flags.female ? "Demigoddess" : "Demigod"));
1521 #else
1522     Sprintf(pbuf, "%s%s\82Ì%s\81D\81D\81D", Goodbye(),
1523             (how != ASCENDED)
1524                 ? (const char *) ((flags.female && urole.name.f)
1525                     ? urole.name.f
1526                     : urole.name.m)
1527                 : (const char *) (flags.female ? "\8f\97\90_" : "\90_"),
1528                 plname);
1529 #endif
1530     dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1531     dump_forward_putstr(endwin, 0, "", done_stopprint);
1532
1533     if (how == ESCAPED || how == ASCENDED) {
1534         struct monst *mtmp;
1535         struct obj *otmp;
1536         register struct val_list *val;
1537         register int i;
1538
1539         for (val = valuables; val->list; val++)
1540             for (i = 0; i < val->size; i++) {
1541                 val->list[i].count = 0L;
1542             }
1543         get_valuables(invent);
1544
1545         /* add points for collected valuables */
1546         for (val = valuables; val->list; val++)
1547             for (i = 0; i < val->size; i++)
1548                 if (val->list[i].count != 0L) {
1549                     tmp = val->list[i].count
1550                           * (long) objects[val->list[i].typ].oc_cost;
1551                     nowrap_add(u.urexp, tmp);
1552                 }
1553
1554         /* count the points for artifacts */
1555         artifact_score(invent, TRUE, endwin);
1556
1557         viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */
1558         mtmp = mydogs;
1559 /*JP
1560             Strcpy(pbuf, "You");
1561 */
1562             Strcpy(pbuf, "\82 \82È\82½");
1563         if (!Schroedingers_cat) /* check here in case disclosure was off */
1564             Schroedingers_cat = odds_and_ends(invent, CAT_CHECK);
1565         if (Schroedingers_cat) {
1566             int mhp, m_lev = adj_lev(&mons[PM_HOUSECAT]);
1567
1568             mhp = d(m_lev, 8);
1569             nowrap_add(u.urexp, mhp);
1570 /*JP
1571                 Strcat(eos(pbuf), " and Schroedinger's cat");
1572 */
1573                 Strcat(eos(pbuf), "\82Æ\83V\83\85\83\8c\83f\83B\83\93\83K\81[\82Ì\94L");
1574         }
1575         if (mtmp) {
1576             while (mtmp) {
1577 /*JP
1578                     Sprintf(eos(pbuf), " and %s", mon_nam(mtmp));
1579 */
1580                     Sprintf(eos(pbuf), "\82Æ%s", mon_nam(mtmp));
1581                 if (mtmp->mtame)
1582                     nowrap_add(u.urexp, mtmp->mhp);
1583                 mtmp = mtmp->nmon;
1584             }
1585 #if 1 /*JP*/
1586             if (!done_stopprint)
1587                 Strcat(pbuf, "\82Í");
1588 #endif
1589             dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1590             pbuf[0] = '\0';
1591         } else {
1592 /*JP
1593                 Strcat(pbuf, " ");
1594 */
1595                 Strcat(pbuf, "\82Í");
1596         }
1597 #if 0 /*JP*/
1598         Sprintf(eos(pbuf), "%s with %ld point%s,",
1599                 how == ASCENDED ? "went to your reward"
1600                                  : "escaped from the dungeon",
1601                 u.urexp, plur(u.urexp));
1602 #else
1603         Sprintf(eos(pbuf), "%ld\83|\83C\83\93\83g\83}\81[\83N\82µ%s\81D",
1604                 u.urexp,
1605                 how==ASCENDED ? "\8f¸\93V\82µ\82½" : "\96À\8b{\82©\82ç\92E\8fo\82µ\82½");
1606 #endif
1607         dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1608
1609         if (!done_stopprint)
1610             artifact_score(invent, FALSE, endwin); /* list artifacts */
1611 #ifdef DUMPLOG
1612         dump_redirect(TRUE);
1613         if (iflags.in_dumplog)
1614             artifact_score(invent, FALSE, 0);
1615         dump_redirect(FALSE);
1616 #endif
1617
1618         /* list valuables here */
1619         for (val = valuables; val->list; val++) {
1620             sort_valuables(val->list, val->size);
1621             for (i = 0; i < val->size && !done_stopprint; i++) {
1622                 int typ = val->list[i].typ;
1623                 long count = val->list[i].count;
1624
1625                 if (count == 0L)
1626                     continue;
1627                 if (objects[typ].oc_class != GEM_CLASS || typ <= LAST_GEM) {
1628                     otmp = mksobj(typ, FALSE, FALSE);
1629                     makeknown(otmp->otyp);
1630                     otmp->known = 1;  /* for fake amulets */
1631                     otmp->dknown = 1; /* seen it (blindness fix) */
1632                     if (has_oname(otmp))
1633                         free_oname(otmp);
1634                     otmp->quan = count;
1635 #if 0 /*JP*/
1636                     Sprintf(pbuf, "%8ld %s (worth %ld %s),", count,
1637                             xname(otmp), count * (long) objects[typ].oc_cost,
1638                             currency(2L));
1639 #else
1640                     Sprintf(pbuf, "%ld\8cÂ\82Ì%s(%ld%s\82Ì\89¿\92l)\81C", count,
1641                             xname(otmp), count * (long) objects[typ].oc_cost,
1642                             currency(2L));
1643 #endif
1644                     obfree(otmp, (struct obj *) 0);
1645                 } else {
1646 #if 0 /*JP*/
1647                     Sprintf(pbuf, "%8ld worthless piece%s of colored glass,",
1648                             count, plur(count));
1649 #else
1650                     Sprintf(pbuf, "%ld\8cÂ\82Ì\89¿\92l\82Ì\82È\82¢\90F\82Â\82«\83K\83\89\83X\81C",
1651                             count);
1652 #endif
1653                 }
1654                 dump_forward_putstr(endwin, 0, pbuf, 0);
1655             }
1656         }
1657
1658     } else {
1659         /* did not escape or ascend */
1660         if (u.uz.dnum == 0 && u.uz.dlevel <= 0) {
1661             /* level teleported out of the dungeon; `how' is DIED,
1662                due to falling or to "arriving at heaven prematurely" */
1663 #if 0 /*JP*/
1664             Sprintf(pbuf, "You %s beyond the confines of the dungeon",
1665                     (u.uz.dlevel < 0) ? "passed away" : ends[how]);
1666 #else
1667             Sprintf(pbuf, "\96À\8b{\82Ì\97Ì\88æ\82ð\89z\82¦%s\81D",
1668                     (u.uz.dlevel < 0) ? "\8fÁ\82¦\82³\82Á\82½" : ends[how]);
1669 #endif
1670         } else {
1671             /* more conventional demise */
1672             const char *where = dungeons[u.uz.dnum].dname;
1673
1674             if (Is_astralevel(&u.uz))
1675 /*JP
1676                 where = "The Astral Plane";
1677 */
1678                 where = "\90¸\97ì\8aE\82É\82Ä";
1679 /*JP
1680             Sprintf(pbuf, "You %s in %s", ends[how], where);
1681 */
1682             Sprintf(pbuf, "\82 \82È\82½\82Í%s", where);
1683             if (!In_endgame(&u.uz) && !Is_knox(&u.uz))
1684 #if 0 /*JP*/
1685                 Sprintf(eos(pbuf), " on dungeon level %d",
1686                         In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz));
1687 #else
1688                 Sprintf(eos(pbuf), "\82Ì\92n\89º%d\8aK\82Å",
1689                         In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz));
1690 #endif
1691         }
1692
1693 /*JP
1694         Sprintf(eos(pbuf), " with %ld point%s,", u.urexp, plur(u.urexp));
1695 */
1696         Sprintf(eos(pbuf), " %ld\83|\83C\83\93\83g\82ð\83}\81[\83N\82µ\81C", u.urexp);
1697         dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1698     }
1699
1700 #if 0 /*JP:T*/
1701     Sprintf(pbuf, "and %ld piece%s of gold, after %ld move%s.", umoney,
1702             plur(umoney), moves, plur(moves));
1703 #else
1704     Sprintf(pbuf, "%ld\96\87\82Ì\8bà\89Ý\82ð\8e\9d\82Á\82Ä\81C%ld\95à\93®\82¢\82½\81D", umoney,
1705             moves);
1706 #endif
1707     dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1708 #if 0 /*JP:T*/
1709     Sprintf(pbuf,
1710             "You were level %d with a maximum of %d hit point%s when you %s.",
1711             u.ulevel, u.uhpmax, plur(u.uhpmax), ends[how]);
1712 #else
1713     Sprintf(pbuf,
1714             "%s\82Æ\82«\81C\82 \82È\82½\82Í\83\8c\83x\83\8b%u\82Å\81C\8dÅ\91å\91Ì\97Í\82Í%d\82Å\82 \82Á\82½\81D",
1715             ends[how],u.ulevel, u.uhpmax);
1716 #endif
1717     dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
1718     dump_forward_putstr(endwin, 0, "", done_stopprint);
1719     if (!done_stopprint)
1720         display_nhwindow(endwin, TRUE);
1721     if (endwin != WIN_ERR)
1722         destroy_nhwindow(endwin);
1723
1724     dump_close_log();
1725     /* "So when I die, the first thing I will see in Heaven is a
1726      * score list?" */
1727     if (have_windows && !iflags.toptenwin)
1728         exit_nhwindows((char *) 0), have_windows = FALSE;
1729     topten(how, endtime);
1730     if (have_windows)
1731         exit_nhwindows((char *) 0);
1732
1733     if (done_stopprint) {
1734         raw_print("");
1735         raw_print("");
1736     }
1737     nh_terminate(EXIT_SUCCESS);
1738 }
1739
1740 void
1741 container_contents(list, identified, all_containers, reportempty)
1742 struct obj *list;
1743 boolean identified, all_containers, reportempty;
1744 {
1745     register struct obj *box, *obj;
1746     char buf[BUFSZ];
1747     boolean cat, deadcat;
1748
1749     for (box = list; box; box = box->nobj) {
1750         if (Is_container(box) || box->otyp == STATUE) {
1751             box->cknown = 1; /* we're looking at the contents now */
1752             if (identified)
1753                 box->lknown = 1;
1754             cat = deadcat = FALSE;
1755             if (SchroedingersBox(box) && !Schroedingers_cat) {
1756                 /* Schroedinger's Cat? */
1757                 cat = odds_and_ends(box, CAT_CHECK);
1758                 if (cat)
1759                     Schroedingers_cat = TRUE;
1760                 else
1761                     deadcat = TRUE;
1762                 box->spe = 0;
1763             }
1764             if (box->otyp == BAG_OF_TRICKS) {
1765                 continue; /* wrong type of container */
1766             } else if (box->cobj) {
1767                 winid tmpwin = create_nhwindow(NHW_MENU);
1768
1769                 sortloot(&box->cobj,
1770                          (((flags.sortloot == 'l' || flags.sortloot == 'f')
1771                            ? SORTLOOT_LOOT : 0)
1772                           | (flags.sortpack ? SORTLOOT_PACK : 0)),
1773                          FALSE);
1774 /*JP
1775                 Sprintf(buf, "Contents of %s:", the(xname(box)));
1776 */
1777                 Sprintf(buf, "%s\82Ì\92\86\90g\81F", the(xname(box)));
1778                 putstr(tmpwin, 0, buf);
1779                 putstr(tmpwin, 0, "");
1780                 for (obj = box->cobj; obj; obj = obj->nobj) {
1781                     if (identified) {
1782                         makeknown(obj->otyp);
1783                         obj->known = obj->bknown = obj->dknown
1784                             = obj->rknown = 1;
1785                         if (Is_container(obj) || obj->otyp == STATUE)
1786                             obj->cknown = obj->lknown = 1;
1787                     }
1788                     putstr(tmpwin, 0, doname(obj));
1789                 }
1790                 if (cat)
1791 /*JP
1792                     putstr(tmpwin, 0, "Schroedinger's cat");
1793 */
1794                     putstr(tmpwin, 0, "\83V\83\85\83\8c\83f\83B\83\93\83K\81[\82Ì\94L");
1795                 else if (deadcat)
1796 /*JP
1797                     putstr(tmpwin, 0, "Schroedinger's dead cat");
1798 */
1799                     putstr(tmpwin, 0, "\83V\83\85\83\8c\83f\83B\83\93\83K\81[\82Ì\94L\82Ì\8e\80\91Ì");
1800                 display_nhwindow(tmpwin, TRUE);
1801                 destroy_nhwindow(tmpwin);
1802                 if (all_containers)
1803                     container_contents(box->cobj, identified, TRUE,
1804                                        reportempty);
1805             } else if (cat || deadcat) {
1806 #if 0 /*JP*/
1807                 pline("%s Schroedinger's %scat!", Tobjnam(box, "contain"),
1808                       deadcat ? "dead " : "");
1809 #else
1810                 pline("%s\82É\82Í\83V\83\85\83\8c\83f\83B\83\93\83K\81[\82Ì\94L%s\82ª\93ü\82Á\82Ä\82¢\82½\81I", xname(box),
1811                       deadcat ? "\82Ì\8e\80\91Ì" : "");
1812 #endif
1813                 display_nhwindow(WIN_MESSAGE, FALSE);
1814             } else if (reportempty) {
1815 /*JP
1816                 pline("%s is empty.", upstart(thesimpleoname(box)));
1817 */
1818                 pline("%s\82Í\8bó\82Á\82Û\82¾\81D", xname(box));
1819                 display_nhwindow(WIN_MESSAGE, FALSE);
1820             }
1821         }
1822         if (!all_containers)
1823             break;
1824     }
1825 }
1826
1827 /* should be called with either EXIT_SUCCESS or EXIT_FAILURE */
1828 void
1829 nh_terminate(status)
1830 int status;
1831 {
1832     program_state.in_moveloop = 0; /* won't be returning to normal play */
1833 #ifdef MAC
1834     getreturn("to exit");
1835 #endif
1836     /* don't bother to try to release memory if we're in panic mode, to
1837        avoid trouble in case that happens to be due to memory problems */
1838     if (!program_state.panicking) {
1839         freedynamicdata();
1840         dlb_cleanup();
1841     }
1842
1843 #ifdef VMS
1844     /*
1845      *  This is liable to draw a warning if compiled with gcc, but it's
1846      *  more important to flag panic() -> really_done() -> nh_terminate()
1847      *  as __noreturn__ then to avoid the warning.
1848      */
1849     /* don't call exit() if already executing within an exit handler;
1850        that would cancel any other pending user-mode handlers */
1851     if (program_state.exiting)
1852         return;
1853 #endif
1854     program_state.exiting = 1;
1855 #if 1 /*JP*/
1856     jputchar('\0'); /* reset terminal */
1857 #endif
1858     nethack_exit(status);
1859 }
1860
1861 extern const int monstr[];
1862
1863 enum vanq_order_modes {
1864     VANQ_MLVL_MNDX = 0,
1865     VANQ_MSTR_MNDX,
1866     VANQ_ALPHA_SEP,
1867     VANQ_ALPHA_MIX,
1868     VANQ_MCLS_HTOL,
1869     VANQ_MCLS_LTOH,
1870     VANQ_COUNT_H_L,
1871     VANQ_COUNT_L_H,
1872
1873     NUM_VANQ_ORDER_MODES
1874 };
1875
1876 static const char *vanqorders[NUM_VANQ_ORDER_MODES] = {
1877     "traditional: by monster level, by internal monster index",
1878     "by monster toughness, by internal monster index",
1879     "alphabetically, first unique monsters, then others",
1880     "alphabetically, unique monsters and others intermixed",
1881     "by monster class, high to low level within class",
1882     "by monster class, low to high level within class",
1883     "by count, high to low, by internal index within tied count",
1884     "by count, low to high, by internal index within tied count",
1885 };
1886 static int vanq_sortmode = VANQ_MLVL_MNDX;
1887
1888 STATIC_PTR int CFDECLSPEC
1889 vanqsort_cmp(vptr1, vptr2)
1890 const genericptr vptr1;
1891 const genericptr vptr2;
1892 {
1893     int indx1 = *(short *) vptr1, indx2 = *(short *) vptr2,
1894         mlev1, mlev2, mstr1, mstr2, uniq1, uniq2, died1, died2, res;
1895     const char *name1, *name2, *punct;
1896     schar mcls1, mcls2;
1897
1898     switch (vanq_sortmode) {
1899     default:
1900     case VANQ_MLVL_MNDX:
1901         /* sort by monster level */
1902         mlev1 = mons[indx1].mlevel, mlev2 = mons[indx2].mlevel;
1903         res = mlev2 - mlev1; /* mlevel high to low */
1904         break;
1905     case VANQ_MSTR_MNDX:
1906         /* sort by monster toughness */
1907         mstr1 = monstr[indx1], mstr2 = monstr[indx2];
1908         res = mstr2 - mstr1; /* monstr high to low */
1909         break;
1910     case VANQ_ALPHA_SEP:
1911         uniq1 = ((mons[indx1].geno & G_UNIQ) && indx1 != PM_HIGH_PRIEST);
1912         uniq2 = ((mons[indx2].geno & G_UNIQ) && indx2 != PM_HIGH_PRIEST);
1913         if (uniq1 ^ uniq2) { /* one or other uniq, but not both */
1914             res = uniq2 - uniq1;
1915             break;
1916         } /* else both unique or neither unique */
1917         /*FALLTHRU*/
1918     case VANQ_ALPHA_MIX:
1919         name1 = mons[indx1].mname, name2 = mons[indx2].mname;
1920         res = strcmpi(name1, name2); /* caseblind alhpa, low to high */
1921         break;
1922     case VANQ_MCLS_HTOL:
1923     case VANQ_MCLS_LTOH:
1924         /* mons[].mlet is a small integer, 1..N, of type plain char;
1925            if 'char' happens to be unsigned, (mlet1 - mlet2) would yield
1926            an inappropriate result when mlet2 is greater than mlet1,
1927            so force our copies (mcls1, mcls2) to be signed */
1928         mcls1 = (schar) mons[indx1].mlet, mcls2 = (schar) mons[indx2].mlet;
1929         /* S_ANT through S_ZRUTY correspond to lowercase monster classes,
1930            S_ANGEL through S_ZOMBIE correspond to uppercase, and various
1931            punctuation characters are used for classes beyond those */
1932         if (mcls1 > S_ZOMBIE && mcls2 > S_ZOMBIE) {
1933             /* force a specific order to the punctuation classes that's
1934                different from the internal order;
1935                internal order is ok if neither or just one is punctuation
1936                since letters have lower values so come out before punct */
1937             static const char punctclasses[] = {
1938                 S_LIZARD, S_EEL, S_GOLEM, S_GHOST, S_DEMON, S_HUMAN, '\0'
1939             };
1940
1941             if ((punct = index(punctclasses, mcls1)) != 0)
1942                 mcls1 = (schar) (S_ZOMBIE + 1 + (int) (punct - punctclasses));
1943             if ((punct = index(punctclasses, mcls2)) != 0)
1944                 mcls2 = (schar) (S_ZOMBIE + 1 + (int) (punct - punctclasses));
1945         }
1946         res = mcls1 - mcls2; /* class */
1947         if (res == 0) {
1948             mlev1 = mons[indx1].mlevel, mlev2 = mons[indx2].mlevel;
1949             res = mlev1 - mlev2; /* mlevel low to high */
1950             if (vanq_sortmode == VANQ_MCLS_HTOL)
1951                 res = -res; /* mlevel high to low */
1952         }
1953         break;
1954     case VANQ_COUNT_H_L:
1955     case VANQ_COUNT_L_H:
1956         died1 = mvitals[indx1].died, died2 = mvitals[indx2].died;
1957         res = died2 - died1; /* dead count high to low */
1958         if (vanq_sortmode == VANQ_COUNT_L_H)
1959             res = -res; /* dead count low to high */
1960         break;
1961     }
1962     /* tiebreaker: internal mons[] index */
1963     if (res == 0)
1964         res = indx1 - indx2; /* mndx low to high */
1965     return res;
1966 }
1967
1968 /* returns -1 if cancelled via ESC */
1969 STATIC_OVL int
1970 set_vanq_order()
1971 {
1972     winid tmpwin;
1973     menu_item *selected;
1974     anything any;
1975     int i, n, choice;
1976
1977     tmpwin = create_nhwindow(NHW_MENU);
1978     start_menu(tmpwin);
1979     any = zeroany; /* zero out all bits */
1980     for (i = 0; i < SIZE(vanqorders); i++) {
1981         if (i == VANQ_ALPHA_MIX || i == VANQ_MCLS_HTOL) /* skip these */
1982             continue;
1983         any.a_int = i + 1;
1984         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, vanqorders[i],
1985                  (i == vanq_sortmode) ? MENU_SELECTED : MENU_UNSELECTED);
1986     }
1987 /*JP
1988     end_menu(tmpwin, "Sort order for vanquished monster counts");
1989 */
1990     end_menu(tmpwin, "\93|\82µ\82½\93G\82Ì\83\\81[\83g\8f\87");
1991
1992     n = select_menu(tmpwin, PICK_ONE, &selected);
1993     destroy_nhwindow(tmpwin);
1994     if (n > 0) {
1995         choice = selected[0].item.a_int - 1;
1996         /* skip preselected entry if we have more than one item chosen */
1997         if (n > 1 && choice == vanq_sortmode)
1998             choice = selected[1].item.a_int - 1;
1999         free((genericptr_t) selected);
2000         vanq_sortmode = choice;
2001     }
2002     return (n < 0) ? -1 : vanq_sortmode;
2003 }
2004
2005 /* #vanquished command */
2006 int
2007 dovanquished()
2008 {
2009     list_vanquished('a', FALSE);
2010     return 0;
2011 }
2012
2013 /* high priests aren't unique but are flagged as such to simplify something */
2014 #define UniqCritterIndx(mndx) ((mons[mndx].geno & G_UNIQ) \
2015                                && mndx != PM_HIGH_PRIEST)
2016
2017 STATIC_OVL void
2018 list_vanquished(defquery, ask)
2019 char defquery;
2020 boolean ask;
2021 {
2022     register int i;
2023     int pfx, nkilled;
2024     unsigned ntypes, ni;
2025     long total_killed = 0L;
2026     winid klwin;
2027     short mindx[NUMMONS];
2028     char c, buf[BUFSZ], buftoo[BUFSZ];
2029     boolean dumping; /* for DUMPLOG; doesn't need to be conditional */
2030
2031     dumping = (defquery == 'd');
2032     if (dumping)
2033         defquery = 'y';
2034
2035     /* get totals first */
2036     ntypes = 0;
2037     for (i = LOW_PM; i < NUMMONS; i++) {
2038         if ((nkilled = (int) mvitals[i].died) == 0)
2039             continue;
2040         mindx[ntypes++] = i;
2041         total_killed += (long) nkilled;
2042     }
2043
2044     /* vanquished creatures list;
2045      * includes all dead monsters, not just those killed by the player
2046      */
2047     if (ntypes != 0) {
2048         char mlet, prev_mlet = 0; /* used as small integer, not character */
2049         boolean class_header, uniq_header, was_uniq = FALSE;
2050
2051 #if 0 /*JP:T*/
2052         c = ask ? yn_function(
2053                             "Do you want an account of creatures vanquished?",
2054                               ynaqchars, defquery)
2055                 : defquery;
2056 #else
2057         c = ask ? yn_function(
2058                             "\93|\82µ\82½\93G\82Ì\88ê\97\97\82ð\8c©\82Ü\82·\82©\81H",
2059                               ynqchars, defquery)
2060                 : defquery;
2061 #endif
2062         if (c == 'q')
2063             done_stopprint++;
2064         if (c == 'y' || c == 'a') {
2065             if (c == 'a') { /* ask player to choose sort order */
2066                 /* choose value for vanq_sortmode via menu; ESC cancels list
2067                    of vanquished monsters but does not set 'done_stopprint' */
2068                 if (set_vanq_order() < 0)
2069                     return;
2070             }
2071             uniq_header = (vanq_sortmode == VANQ_ALPHA_SEP);
2072             class_header = (vanq_sortmode == VANQ_MCLS_LTOH
2073                             || vanq_sortmode == VANQ_MCLS_HTOL);
2074
2075             klwin = create_nhwindow(NHW_MENU);
2076 /*JP
2077             putstr(klwin, 0, "Vanquished creatures:");
2078 */
2079             putstr(klwin, 0, "\93|\82µ\82½\93G\81F");
2080             if (!dumping)
2081                 putstr(klwin, 0, "");
2082
2083             qsort((genericptr_t) mindx, ntypes, sizeof *mindx, vanqsort_cmp);
2084             for (ni = 0; ni < ntypes; ni++) {
2085                 i = mindx[ni];
2086                 nkilled = mvitals[i].died;
2087                 mlet = mons[i].mlet;
2088                 if (class_header && mlet != prev_mlet) {
2089                     Strcpy(buf, def_monsyms[(int) mlet].explain);
2090                     putstr(klwin, ask ? 0 : iflags.menu_headings,
2091                            upstart(buf));
2092                     prev_mlet = mlet;
2093                 }
2094                 if (UniqCritterIndx(i)) {
2095 #if 0 /*JP*/
2096                     Sprintf(buf, "%s%s",
2097                             !type_is_pname(&mons[i]) ? "the " : "",
2098                             mons[i].mname);
2099 #else
2100                     Sprintf(buf, "%s", mons[i].mname);
2101 #endif
2102                     if (nkilled > 1) {
2103 #if 0 /*JP*/
2104                         switch (nkilled) {
2105                         case 2:
2106                             Sprintf(eos(buf), " (twice)");
2107                             break;
2108                         case 3:
2109                             Sprintf(eos(buf), " (thrice)");
2110                             break;
2111                         default:
2112                             Sprintf(eos(buf), " (%d times)", nkilled);
2113                             break;
2114                         }
2115 #else
2116                         Sprintf(eos(buf)," (%d\89ñ)", nkilled);
2117 #endif
2118                     }
2119                     was_uniq = TRUE;
2120                 } else {
2121                     if (uniq_header && was_uniq) {
2122                         putstr(klwin, 0, "");
2123                         was_uniq = FALSE;
2124                     }
2125                     /* trolls or undead might have come back,
2126                        but we don't keep track of that */
2127                     if (nkilled == 1)
2128                         Strcpy(buf, an(mons[i].mname));
2129                     else
2130 #if 0 /*JP:T*/
2131                         Sprintf(buf, "%3d %s", nkilled,
2132                                 makeplural(mons[i].mname));
2133 #else
2134                         Sprintf(buf, "%d\91Ì\82Ì%s", nkilled,
2135                                 mons[i].mname);
2136 #endif
2137                 }
2138                 /* number of leading spaces to match 3 digit prefix */
2139 #if 0 /*JP*/
2140                 pfx = !strncmpi(buf, "the ", 3) ? 0
2141                       : !strncmpi(buf, "an ", 3) ? 1
2142                         : !strncmpi(buf, "a ", 2) ? 2
2143                           : !digit(buf[2]) ? 4 : 0;
2144 #else
2145                 pfx = !digit(buf[2]) ? 4 : 0;
2146 #endif
2147                 if (class_header)
2148                     ++pfx;
2149                 Sprintf(buftoo, "%*s%s", pfx, "", buf);
2150                 putstr(klwin, 0, buftoo);
2151             }
2152             /*
2153              * if (Hallucination)
2154              *     putstr(klwin, 0, "and a partridge in a pear tree");
2155              */
2156             if (ntypes > 1) {
2157                 if (!dumping)
2158                     putstr(klwin, 0, "");
2159 /*JP
2160                 Sprintf(buf, "%ld creatures vanquished.", total_killed);
2161 */
2162                 Sprintf(buf, "%ld\95C\82Ì\93G\82ð\93|\82µ\82½\81D", total_killed);
2163                 putstr(klwin, 0, buf);
2164             }
2165             display_nhwindow(klwin, TRUE);
2166             destroy_nhwindow(klwin);
2167         }
2168     } else if (defquery == 'a') {
2169         /* #dovanquished rather than final disclosure, so pline() is ok */
2170 /*JP
2171         pline("No creatures have been vanquished.");
2172 */
2173         pline("\93|\82µ\82½\93G\82Í\82¢\82È\82©\82Á\82½\81D");
2174 #ifdef DUMPLOG
2175     } else if (dumping) {
2176         putstr(0, 0, "No creatures were vanquished."); /* not pline() */
2177 #endif
2178     }
2179 }
2180
2181 /* number of monster species which have been genocided */
2182 int
2183 num_genocides()
2184 {
2185     int i, n = 0;
2186
2187     for (i = LOW_PM; i < NUMMONS; ++i) {
2188         if (mvitals[i].mvflags & G_GENOD) {
2189             ++n;
2190             if (UniqCritterIndx(i))
2191                 impossible("unique creature '%d: %s' genocided?",
2192                            i, mons[i].mname);
2193         }
2194     }
2195     return n;
2196 }
2197
2198 STATIC_OVL int
2199 num_extinct()
2200 {
2201     int i, n = 0;
2202
2203     for (i = LOW_PM; i < NUMMONS; ++i) {
2204         if (UniqCritterIndx(i))
2205             continue;
2206         if ((mvitals[i].mvflags & G_GONE) == G_EXTINCT)
2207             ++n;
2208     }
2209     return n;
2210 }
2211
2212 STATIC_OVL void
2213 list_genocided(defquery, ask)
2214 char defquery;
2215 boolean ask;
2216 {
2217     register int i;
2218     int ngenocided, nextinct;
2219     char c;
2220     winid klwin;
2221     char buf[BUFSZ];
2222     boolean dumping; /* for DUMPLOG; doesn't need to be conditional */
2223
2224     dumping = (defquery == 'd');
2225     if (dumping)
2226         defquery = 'y';
2227
2228     ngenocided = num_genocides();
2229     nextinct = num_extinct();
2230
2231     /* genocided or extinct species list */
2232     if (ngenocided != 0 || nextinct != 0) {
2233 #if 0 /*JP:T*/
2234         Sprintf(buf, "Do you want a list of %sspecies%s%s?",
2235                 (nextinct && !ngenocided) ? "extinct " : "",
2236                 (ngenocided) ? " genocided" : "",
2237                 (nextinct && ngenocided) ? " and extinct" : "");
2238 #else
2239         Sprintf(buf, "%s%s%s\82µ\82½\8eí\82Ì\88ê\97\97\82ð\8c©\82Ü\82·\82©\81H",
2240                 (nextinct && !ngenocided) ? "\90â\96Å" : "",
2241                 (ngenocided) ? "\8bs\8eE" : "",
2242                 (nextinct && ngenocided) ? "\82¨\82æ\82Ñ\90â\96Å" : "");
2243 #endif
2244         c = ask ? yn_function(buf, ynqchars, defquery) : defquery;
2245         if (c == 'q')
2246             done_stopprint++;
2247         if (c == 'y') {
2248             klwin = create_nhwindow(NHW_MENU);
2249 #if 0 /*JP*/
2250             Sprintf(buf, "%s%s species:",
2251                     (ngenocided) ? "Genocided" : "Extinct",
2252                     (nextinct && ngenocided) ? " or extinct" : "");
2253 #else
2254             Sprintf(buf, "%s%s\82µ\82½\8eí:",
2255                     (ngenocided) ? "\8bs\8eE" : "\90â\96Å",
2256                     (nextinct && ngenocided) ? "\82Ü\82½\82Í\90â\96Å" : "");
2257 #endif
2258             putstr(klwin, 0, buf);
2259             if (!dumping)
2260                 putstr(klwin, 0, "");
2261
2262             for (i = LOW_PM; i < NUMMONS; i++) {
2263                 /* uniques can't be genocided but can become extinct;
2264                    however, they're never reported as extinct, so skip them */
2265                 if (UniqCritterIndx(i))
2266                     continue;
2267                 if (mvitals[i].mvflags & G_GONE) {
2268                     Sprintf(buf, " %s", makeplural(mons[i].mname));
2269                     /*
2270                      * "Extinct" is unfortunate terminology.  A species
2271                      * is marked extinct when its birth limit is reached,
2272                      * but there might be members of the species still
2273                      * alive, contradicting the meaning of the word.
2274                      */
2275                     if ((mvitals[i].mvflags & G_GONE) == G_EXTINCT)
2276 /*JP
2277                         Strcat(buf, " (extinct)");
2278 */
2279                         Strcat(buf, "(\90â\96Å)");
2280                     putstr(klwin, 0, buf);
2281                 }
2282             }
2283             if (!dumping)
2284                 putstr(klwin, 0, "");
2285             if (ngenocided > 0) {
2286 /*JP
2287                 Sprintf(buf, "%d species genocided.", ngenocided);
2288 */
2289                 Sprintf(buf, "%d\8eí\97Þ\82Ì\8eí\82ð\8bs\8eE\82µ\82½\81D", ngenocided);
2290                 putstr(klwin, 0, buf);
2291             }
2292             if (nextinct > 0) {
2293 /*JP
2294                 Sprintf(buf, "%d species extinct.", nextinct);
2295 */
2296                 Sprintf(buf, "%d\8eí\97Þ\82Ì\8eí\82ð\90â\96Å\82³\82¹\82½\81D", nextinct);
2297                 putstr(klwin, 0, buf);
2298             }
2299
2300             display_nhwindow(klwin, TRUE);
2301             destroy_nhwindow(klwin);
2302         }
2303 #ifdef DUMPLOG
2304     } else if (dumping) {
2305         putstr(0, 0, "No species were genocided or became extinct.");
2306 #endif
2307     }
2308 }
2309
2310 /* set a delayed killer, ensure non-delayed killer is cleared out */
2311 void
2312 delayed_killer(id, format, killername)
2313 int id;
2314 int format;
2315 const char *killername;
2316 {
2317     struct kinfo *k = find_delayed_killer(id);
2318
2319     if (k == (struct kinfo *) 0) {
2320         /* no match, add a new delayed killer to the list */
2321         k = (struct kinfo *) alloc(sizeof(struct kinfo));
2322         (void) memset((genericptr_t)k, 0, sizeof(struct kinfo));
2323         k->id = id;
2324         k->next = killer.next;
2325         killer.next = k;
2326     }
2327
2328     k->format = format;
2329     Strcpy(k->name, killername ? killername : "");
2330     killer.name[0] = 0;
2331 }
2332
2333 struct kinfo *
2334 find_delayed_killer(id)
2335 int id;
2336 {
2337     struct kinfo *k;
2338
2339     for (k = killer.next; k != (struct kinfo *) 0; k = k->next) {
2340         if (k->id == id)
2341             break;
2342     }
2343     return k;
2344 }
2345
2346 void
2347 dealloc_killer(kptr)
2348 struct kinfo *kptr;
2349 {
2350     struct kinfo *prev = &killer, *k;
2351
2352     if (kptr == (struct kinfo *) 0)
2353         return;
2354     for (k = killer.next; k != (struct kinfo *) 0; k = k->next) {
2355         if (k == kptr)
2356             break;
2357         prev = k;
2358     }
2359
2360     if (k == (struct kinfo *) 0) {
2361         impossible("dealloc_killer not on list");
2362     } else {
2363         prev->next = k->next;
2364         free((genericptr_t) k);
2365     }
2366 }
2367
2368 void
2369 save_killers(fd, mode)
2370 int fd;
2371 int mode;
2372 {
2373     struct kinfo *kptr;
2374
2375     if (perform_bwrite(mode)) {
2376         for (kptr = &killer; kptr != (struct kinfo *) 0; kptr = kptr->next) {
2377             bwrite(fd, (genericptr_t) kptr, sizeof(struct kinfo));
2378         }
2379     }
2380     if (release_data(mode)) {
2381         while (killer.next) {
2382             kptr = killer.next->next;
2383             free((genericptr_t) killer.next);
2384             killer.next = kptr;
2385         }
2386     }
2387 }
2388
2389 void
2390 restore_killers(fd)
2391 int fd;
2392 {
2393     struct kinfo *kptr;
2394
2395     for (kptr = &killer; kptr != (struct kinfo *) 0; kptr = kptr->next) {
2396         mread(fd, (genericptr_t) kptr, sizeof(struct kinfo));
2397         if (kptr->next) {
2398             kptr->next = (struct kinfo *) alloc(sizeof(struct kinfo));
2399         }
2400     }
2401 }
2402
2403 static int
2404 wordcount(p)
2405 char *p;
2406 {
2407     int words = 0;
2408
2409     while (*p) {
2410         while (*p && isspace((uchar) *p))
2411             p++;
2412         if (*p)
2413             words++;
2414         while (*p && !isspace((uchar) *p))
2415             p++;
2416     }
2417     return words;
2418 }
2419
2420 static void
2421 bel_copy1(inp, out)
2422 char **inp, *out;
2423 {
2424     char *in = *inp;
2425
2426     out += strlen(out); /* eos() */
2427     while (*in && isspace((uchar) *in))
2428         in++;
2429     while (*in && !isspace((uchar) *in))
2430         *out++ = *in++;
2431     *out = '\0';
2432     *inp = in;
2433 }
2434
2435 /*JP: files.c\82Å1\83\96\8f\8a\8eg\82í\82ê\82Ä\82¢\82é\82ª\82±\82±\82Í\89p\8cê\82Ì\82Ü\82Ü\82É\82µ\82Ä\82¨\82­*/
2436 char *
2437 build_english_list(in)
2438 char *in;
2439 {
2440     char *out, *p = in;
2441     int len = (int) strlen(p), words = wordcount(p);
2442
2443     /* +3: " or " - " "; +(words - 1): (N-1)*(", " - " ") */
2444     if (words > 1)
2445         len += 3 + (words - 1);
2446     out = (char *) alloc(len + 1);
2447     *out = '\0'; /* bel_copy1() appends */
2448
2449     switch (words) {
2450     case 0:
2451         impossible("no words in list");
2452         break;
2453     case 1:
2454         /* "single" */
2455         bel_copy1(&p, out);
2456         break;
2457     default:
2458         if (words == 2) {
2459             /* "first or second" */
2460             bel_copy1(&p, out);
2461             Strcat(out, " ");
2462         } else {
2463             /* "first, second, or third */
2464             do {
2465                 bel_copy1(&p, out);
2466                 Strcat(out, ", ");
2467             } while (--words > 1);
2468         }
2469         Strcat(out, "or ");
2470         bel_copy1(&p, out);
2471         break;
2472     }
2473     return out;
2474 }
2475
2476 /*end.c*/