1 /* SCCS Id: @(#)end.c 3.4 2003/03/10 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 #define NEED_VARARGS /* comment line for pre-compiled headers */
14 /* these probably ought to be generated by makedefs, like LAST_GEM */
15 #define FIRST_GEM DILITHIUM_CRYSTAL
16 #define FIRST_AMULET AMULET_OF_ESP
17 #define LAST_AMULET AMULET_OF_YENDOR
19 struct valuable_data { long count; int typ; };
21 static struct valuable_data
22 gems[LAST_GEM+1 - FIRST_GEM + 1], /* 1 extra for glass */
23 amulets[LAST_AMULET+1 - FIRST_AMULET];
25 static struct val_list { struct valuable_data *list; int size; } valuables[] = {
26 { gems, sizeof gems / sizeof *gems },
27 { amulets, sizeof amulets / sizeof *amulets },
32 STATIC_PTR void FDECL(done_intr, (int));
33 # if defined(UNIX) || defined(VMS) || defined (__EMX__)
34 static void FDECL(done_hangup, (int));
37 STATIC_DCL void FDECL(disclose,(int,BOOLEAN_P));
38 STATIC_DCL void FDECL(get_valuables, (struct obj *));
39 STATIC_DCL void FDECL(sort_valuables, (struct valuable_data *,int));
40 STATIC_DCL void FDECL(artifact_score, (struct obj *,BOOLEAN_P,winid));
41 STATIC_DCL void FDECL(savelife, (int));
42 STATIC_DCL void FDECL(list_vanquished, (CHAR_P,BOOLEAN_P));
43 STATIC_DCL void FDECL(list_genocided, (CHAR_P,BOOLEAN_P));
44 STATIC_DCL boolean FDECL(should_query_disclose_option, (int,char *));
46 #if defined(__BEOS__) || defined(MICRO) || defined(WIN32) || defined(OS2)
47 extern void FDECL(nethack_exit,(int));
49 #define nethack_exit exit
52 #define done_stopprint program_state.stopprint
55 # define NH_abort() Abort(0)
58 # define NH_abort() (void) abort()
61 # define NH_abort() win32_abort()
63 # define NH_abort() abort()
69 * The order of these needs to match the macros in hack.h.
71 static NEARDATA const char *deaths[] = { /* the array of death */
72 "died", "choked", "poisoned", "starvation", "drowning",
73 "burning", "dissolving under the heat and pressure",
74 "crushed", "turned to stone", "turned into slime",
75 "genocided", "panic", "trickery",
76 "quit", "escaped", "ascended"
79 static NEARDATA const char *ends[] = { /* "when you..." */
80 "died", "choked", "were poisoned", "starved", "drowned",
81 "burned", "dissolved in the lava",
82 "were crushed", "turned to stone", "turned into slime",
83 "were genocided", "panicked", "were tricked",
84 "quit", "escaped", "ascended"
87 extern const char * const killed_by_prefix[]; /* from topten.c */
91 done1(sig_unused) /* called as signal() handler, so sent at least one arg */
95 (void) signal(SIGINT,SIG_IGN);
99 (void) signal(SIGINT, (SIG_RET_TYPE) done1);
101 clear_nhwindow(WIN_MESSAGE);
104 if(multi > 0) nomul(0);
111 /* "#quit" command or keyboard interrupt */
115 if(yn("Really quit?") == 'n') {
117 (void) signal(SIGINT, (SIG_RET_TYPE) done1);
119 clear_nhwindow(WIN_MESSAGE);
122 if(multi > 0) nomul(0);
124 u.uinvulnerable = FALSE; /* avoid ctrl-C bug -dlc */
129 #if defined(WIZARD) && (defined(UNIX) || defined(VMS) || defined(LATTICE))
133 const char *tmp = "Enter debugger?";
136 const char *tmp = "Create SnapShot?";
138 const char *tmp = "Dump core?";
141 if ((c = ynq(tmp)) == 'y') {
142 (void) signal(SIGINT, (SIG_RET_TYPE) done1);
143 exit_nhwindows((char *)0);
145 } else if (c == 'q') done_stopprint++;
157 done_intr(sig_unused) /* called as signal() handler, so sent at least one arg */
161 (void) signal(SIGINT, SIG_IGN);
162 # if defined(UNIX) || defined(VMS)
163 (void) signal(SIGQUIT, SIG_IGN);
168 # if defined(UNIX) || defined(VMS) || defined(__EMX__)
170 done_hangup(sig) /* signal() handler */
173 program_state.done_hup++;
174 (void)signal(SIGHUP, SIG_IGN);
179 #endif /* NO_SIGNAL */
183 register struct monst *mtmp;
186 boolean distorted = (boolean)(Hallucination && canspotmon(mtmp));
189 mark_synch(); /* flush buffered screen output */
191 killer_format = KILLED_BY_AN;
192 /* "killed by the high priest of Crom" is okay, "killed by the high
193 priest" alone isn't */
194 if ((mtmp->data->geno & G_UNIQ) != 0 && !(mtmp->data == &mons[PM_HIGH_PRIEST] && !mtmp->ispriest)) {
195 if (!type_is_pname(mtmp->data))
197 killer_format = KILLED_BY;
199 /* _the_ <invisible> <distorted> ghost of Dudley */
200 if (mtmp->data == &mons[PM_GHOST] && mtmp->mnamelth) {
202 killer_format = KILLED_BY;
205 Strcat(buf, "invisible ");
207 Strcat(buf, "hallucinogen-distorted ");
209 if(mtmp->data == &mons[PM_GHOST]) {
210 Strcat(buf, "ghost");
211 if (mtmp->mnamelth) Sprintf(eos(buf), " of %s", NAME(mtmp));
212 } else if(mtmp->isshk) {
213 Sprintf(eos(buf), "%s %s, the shopkeeper",
214 (mtmp->female ? "Ms." : "Mr."), shkname(mtmp));
215 killer_format = KILLED_BY;
216 } else if (mtmp->ispriest || mtmp->isminion) {
217 /* m_monnam() suppresses "the" prefix plus "invisible", and
218 it overrides the effect of Hallucination on priestname() */
219 killer = m_monnam(mtmp);
222 Strcat(buf, mtmp->data->mname);
224 Sprintf(eos(buf), " called %s", NAME(mtmp));
227 if (multi) Strcat(buf, ", while helpless");
229 if (mtmp->data->mlet == S_WRAITH)
230 u.ugrave_arise = PM_WRAITH;
231 else if (mtmp->data->mlet == S_MUMMY && urace.mummynum != NON_PM)
232 u.ugrave_arise = urace.mummynum;
233 else if (mtmp->data->mlet == S_VAMPIRE && Race_if(PM_HUMAN))
234 u.ugrave_arise = PM_VAMPIRE;
235 else if (mtmp->data == &mons[PM_GHOUL])
236 u.ugrave_arise = PM_GHOUL;
237 if (u.ugrave_arise >= LOW_PM &&
238 (mvitals[u.ugrave_arise].mvflags & G_GENOD))
239 u.ugrave_arise = NON_PM;
240 if (touch_petrifies(mtmp->data))
248 #define NOTIFY_NETHACK_BUGS
253 panic VA_DECL(const char *, str)
255 VA_INIT(str, char *);
257 if (program_state.panicking++)
258 NH_abort(); /* avoid loops - this should never happen*/
260 if (iflags.window_inited) {
261 raw_print("\r\nOops...");
262 wait_synch(); /* make sure all pending output gets flushed */
263 exit_nhwindows((char *)0);
264 iflags.window_inited = 0; /* they're gone; force raw_print()ing */
267 raw_print(program_state.gameover ?
268 "Postgame wrapup disrupted." :
269 !program_state.something_worth_saving ?
270 "Program initialization has failed." :
271 "Suddenly, the dungeon collapses.");
272 #if defined(WIZARD) && !defined(MICRO)
273 # if defined(NOTIFY_NETHACK_BUGS)
275 raw_printf("Report the following error to \"%s\".",
276 "nethack-bugs@nethack.org");
277 else if (program_state.something_worth_saving)
278 raw_print("\nError save file being written.\n");
281 raw_printf("Report error to \"%s\"%s.",
282 # ifdef WIZARD_NAME /*(KR1ED)*/
287 !program_state.something_worth_saving ? "" :
288 " and it may be possible to rebuild.");
290 if (program_state.something_worth_saving) {
291 set_error_savefile();
297 Vsprintf(buf,str,VA_ARGS);
299 paniclog("panic", buf);
302 interject(INTERJECT_PANIC);
304 #if defined(WIZARD) && (defined(UNIX) || defined(VMS) || defined(LATTICE) || defined(WIN32))
306 NH_abort(); /* generate core dump */
313 should_query_disclose_option(category, defquery)
318 char *dop = index(disclosure_options, category);
320 if (dop && defquery) {
321 idx = dop - disclosure_options;
322 if (idx < 0 || idx > (NUM_DISCLOSURE_OPTIONS - 1)) {
324 "should_query_disclose_option: bad disclosure index %d %c",
326 *defquery = DISCLOSE_PROMPT_DEFAULT_YES;
329 if (flags.end_disclose[idx] == DISCLOSE_YES_WITHOUT_PROMPT) {
332 } else if (flags.end_disclose[idx] == DISCLOSE_NO_WITHOUT_PROMPT) {
335 } else if (flags.end_disclose[idx] == DISCLOSE_PROMPT_DEFAULT_YES) {
338 } else if (flags.end_disclose[idx] == DISCLOSE_PROMPT_DEFAULT_NO) {
344 impossible("should_query_disclose_option: bad category %c", category);
346 impossible("should_query_disclose_option: null defquery");
355 char c = 0, defquery;
361 Sprintf(qbuf,"Do you want to see what you had when you %s?",
362 (how == QUIT) ? "quit" : "died");
364 Strcpy(qbuf,"Do you want your possessions identified?");
366 ask = should_query_disclose_option('i', &defquery);
367 if (!done_stopprint) {
368 c = ask ? yn_function(qbuf, ynqchars, defquery) : defquery;
372 for (obj = invent; obj; obj = obj->nobj) {
373 makeknown(obj->otyp);
374 obj->known = obj->bknown = obj->dknown = obj->rknown = 1;
376 (void) display_inventory((char *)0, TRUE);
377 container_contents(invent, TRUE, TRUE);
379 if (c == 'q') done_stopprint++;
383 ask = should_query_disclose_option('a', &defquery);
384 if (!done_stopprint) {
385 c = ask ? yn_function("Do you want to see your attributes?",
386 ynqchars, defquery) : defquery;
388 enlightenment(how >= PANICKED ? 1 : 2); /* final */
389 if (c == 'q') done_stopprint++;
392 ask = should_query_disclose_option('v', &defquery);
394 list_vanquished(defquery, ask);
396 ask = should_query_disclose_option('g', &defquery);
398 list_genocided(defquery, ask);
400 ask = should_query_disclose_option('c', &defquery);
401 if (!done_stopprint) {
402 c = ask ? yn_function("Do you want to see your conduct?",
403 ynqchars, defquery) : defquery;
405 show_conduct(how >= PANICKED ? 1 : 2);
406 if (c == 'q') done_stopprint++;
410 /* try to get the player back in a viable state after being killed */
417 if (u.uhunger < 500) {
421 /* cure impending doom of sickness hero won't have time to fix */
422 if ((Sick & TIMEOUT) == 1) {
426 if (how == CHOKING) init_uhunger();
427 nomovemsg = "You survived that attempt on your life.";
429 if(multi > 0) multi = 0; else multi = -1;
430 if(u.utrap && u.utraptype == TT_LAVA) u.utrap = 0;
432 u.ugrave_arise = NON_PM;
438 * Get valuables from the given list. Revised code: the list always remains
443 struct obj *list; /* inventory or container contents */
445 register struct obj *obj;
448 /* find amulets and gems, ignoring all artifacts */
449 for (obj = list; obj; obj = obj->nobj)
450 if (Has_contents(obj)) {
451 get_valuables(obj->cobj);
452 } else if (obj->oartifact) {
454 } else if (obj->oclass == AMULET_CLASS) {
455 i = obj->otyp - FIRST_AMULET;
456 if (!amulets[i].count) {
457 amulets[i].count = obj->quan;
458 amulets[i].typ = obj->otyp;
459 } else amulets[i].count += obj->quan; /* always adds one */
460 } else if (obj->oclass == GEM_CLASS && obj->otyp < LUCKSTONE) {
461 i = min(obj->otyp, LAST_GEM + 1) - FIRST_GEM;
462 if (!gems[i].count) {
463 gems[i].count = obj->quan;
464 gems[i].typ = obj->otyp;
465 } else gems[i].count += obj->quan;
471 * Sort collected valuables, most frequent to least. We could just
472 * as easily use qsort, but we don't care about efficiency here.
475 sort_valuables(list, size)
476 struct valuable_data list[];
477 int size; /* max value is less than 20 */
480 struct valuable_data ltmp;
482 /* move greater quantities to the front of the list */
483 for (i = 1; i < size; i++) {
484 if (list[i].count == 0) continue; /* empty slot */
485 ltmp = list[i]; /* structure copy */
486 for (j = i; j > 0; --j)
487 if (list[j-1].count >= ltmp.count) break;
496 /* called twice; first to calculate total, then to list relevant items */
498 artifact_score(list, counting, endwin)
500 boolean counting; /* true => add up points; false => display them */
506 short dummy; /* object type returned by artifact_name() */
508 for (otmp = list; otmp; otmp = otmp->nobj) {
509 if (otmp->oartifact ||
510 otmp->otyp == BELL_OF_OPENING ||
511 otmp->otyp == SPE_BOOK_OF_THE_DEAD ||
512 otmp->otyp == CANDELABRUM_OF_INVOCATION) {
513 value = arti_cost(otmp); /* zorkmid value */
514 points = value * 5 / 2; /* score value */
518 makeknown(otmp->otyp);
519 otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
520 /* assumes artifacts don't have quan > 1 */
521 Sprintf(pbuf, "%s%s (worth %ld %s and %ld points)",
522 the_unique_obj(otmp) ? "The " : "",
523 otmp->oartifact ? artifact_name(xname(otmp), &dummy) :
524 OBJ_NAME(objects[otmp->otyp]),
525 value, currency(value), points);
526 putstr(endwin, 0, pbuf);
529 if (Has_contents(otmp))
530 artifact_score(otmp->cobj, counting, endwin);
534 /* Be careful not to call panic from here! */
540 char kilbuf[BUFSZ], pbuf[BUFSZ];
541 winid endwin = WIN_ERR;
542 boolean bones_ok, have_windows = iflags.window_inited;
543 struct obj *corpse = (struct obj *)0;
546 if (how == TRICKED) {
548 paniclog("trickery", killer);
553 You("are a very tricky wizard, it seems.");
559 /* kilbuf: used to copy killer in case it comes from something like
560 * xname(), which would otherwise get overwritten when we call
561 * xname() when listing possessions
562 * pbuf: holds Sprintf'd output for raw_print and putstr
564 if (how == ASCENDED || (!killer && how == GENOCIDED))
565 killer_format = NO_KILLER_PREFIX;
566 /* Avoid killed by "a" burning or "a" starvation */
567 if (!killer && (how == STARVING || how == BURNING))
568 killer_format = KILLED_BY;
569 Strcpy(kilbuf, (!killer || how >= PANICKED ? deaths[how] : killer));
572 if (how < PANICKED) u.umortality++;
573 if (Lifesaved && (how <= GENOCIDED)) {
574 pline("But wait...");
575 makeknown(AMULET_OF_LIFE_SAVING);
576 Your("medallion %s!",
577 !Blind ? "begins to glow" : "feels warm");
578 if (how == CHOKING) You("vomit ...");
579 You_feel("much better!");
580 pline_The("medallion crumbles to dust!");
581 if (uamul) useup(uamul);
583 (void) adjattrib(A_CON, -1, TRUE);
584 if(u.uhpmax <= 0) u.uhpmax = 10; /* arbitrary */
586 if (how == GENOCIDED)
587 pline("Unfortunately you are still genocided...");
598 discover) && (how <= GENOCIDED)) {
599 if(yn("Die?") == 'y') goto die;
600 pline("OK, so you don't %s.",
601 (how == CHOKING) ? "choke" : "die");
602 if(u.uhpmax <= 0) u.uhpmax = u.ulevel * 8; /* arbitrary */
610 * The game is now over...
614 program_state.gameover = 1;
615 /* in case of a subsequent panic(), there's no point trying to save */
616 program_state.something_worth_saving = 0;
617 /* render vision subsystem inoperative */
618 iflags.vision_inited = 0;
619 /* might have been killed while using a disposable item, so make sure
620 it's gone prior to inventory disclosure and creation of bones data */
623 /* Sometimes you die on the first move. Life's not fair.
624 * On those rare occasions you get hosed immediately, go out
627 if (moves <= 1 && how < PANICKED) /* You die... --More-- */
628 pline("Do not pass go. Do not collect 200 %s.", currency(200L));
630 if (have_windows) wait_synch(); /* flush screen output */
632 (void) signal(SIGINT, (SIG_RET_TYPE) done_intr);
633 # if defined(UNIX) || defined(VMS) || defined (__EMX__)
634 (void) signal(SIGQUIT, (SIG_RET_TYPE) done_intr);
635 (void) signal(SIGHUP, (SIG_RET_TYPE) done_hangup);
637 #endif /* NO_SIGNAL */
639 bones_ok = (how < GENOCIDED) && can_make_bones();
641 if (how == TURNED_SLIME)
642 u.ugrave_arise = PM_GREEN_SLIME;
644 if (bones_ok && u.ugrave_arise < LOW_PM) {
645 /* corpse gets burnt up too */
647 u.ugrave_arise = (NON_PM - 2); /* leave no corpse */
648 else if (how == STONING)
649 u.ugrave_arise = (NON_PM - 1); /* statue instead of corpse */
650 else if (u.ugrave_arise == NON_PM &&
651 !(mvitals[u.umonnum].mvflags & G_NOCORPSE)) {
652 int mnum = u.umonnum;
655 /* Base corpse on race when not poly'd since original
656 * u.umonnum is based on role, and all role monsters
659 mnum = (flags.female && urace.femalenum != NON_PM) ?
660 urace.femalenum : urace.malenum;
662 corpse = mk_named_object(CORPSE, &mons[mnum],
664 Sprintf(pbuf, "%s, %s%s", plname,
665 killer_format == NO_KILLER_PREFIX ? "" :
666 killed_by_prefix[how],
667 killer_format == KILLED_BY_AN ? an(killer) : killer);
668 make_grave(u.ux, u.uy, pbuf);
673 killer_format = NO_KILLER_PREFIX;
676 u.umortality++; /* skipped above when how==QUIT */
677 /* note that killer is pointing at kilbuf */
678 Strcpy(kilbuf, "quit while already on Charon's boat");
681 if (how == ESCAPED || how == PANICKED)
682 killer_format = NO_KILLER_PREFIX;
684 if (how != PANICKED) {
685 /* these affect score and/or bones, but avoid them during panic */
686 taken = paybill((how == ESCAPED) ? -1 : (how != QUIT));
689 } else taken = FALSE; /* lint; assert( !bones_ok ); */
693 if (have_windows) display_nhwindow(WIN_MESSAGE, FALSE);
695 if (strcmp(flags.end_disclose, "none") && how != PANICKED)
696 disclose(how, taken);
697 /* finish_paybill should be called after disclosure but before bones */
698 if (bones_ok && taken) finish_paybill();
700 /* calculate score, before creating bones [container gold] */
703 int deepest = deepest_lev_reached(FALSE);
709 umoney = money_cnt(invent);
712 umoney += hidden_gold(); /* accumulate gold from containers */
713 tmp = umoney - tmp; /* net gain */
720 u.urexp += 50L * (long)(deepest - 1);
722 u.urexp += 1000L * (long)((deepest > 30) ? 10 : deepest - 20);
723 if (how == ASCENDED) u.urexp *= 2L;
728 if (!wizard || yn("Save bones?") == 'y')
731 /* corpse may be invalid pointer now so
732 ensure that it isn't used again */
733 corpse = (struct obj *)0;
736 /* update gold for the rip output, which can't use hidden_gold()
737 (containers will be gone by then if bones just got saved...) */
744 /* clean up unneeded windows */
747 display_nhwindow(WIN_MESSAGE, TRUE);
748 destroy_nhwindow(WIN_MAP);
749 destroy_nhwindow(WIN_STATUS);
750 destroy_nhwindow(WIN_MESSAGE);
751 WIN_MESSAGE = WIN_STATUS = WIN_MAP = WIN_ERR;
753 if(!done_stopprint || flags.tombstone)
754 endwin = create_nhwindow(NHW_TEXT);
756 if (how < GENOCIDED && flags.tombstone && endwin != WIN_ERR)
759 done_stopprint = 1; /* just avoid any more output */
761 /* changing kilbuf really changes killer. we do it this way because
762 killer is declared a (const char *)
764 if (u.uhave.amulet) Strcat(kilbuf, " (with the Amulet)");
765 else if (how == ESCAPED) {
766 if (Is_astralevel(&u.uz)) /* offered Amulet to wrong deity */
767 Strcat(kilbuf, " (in celestial disgrace)");
768 else if (carrying(FAKE_AMULET_OF_YENDOR))
769 Strcat(kilbuf, " (with a fake Amulet)");
770 /* don't bother counting to see whether it should be plural */
773 if (!done_stopprint) {
774 Sprintf(pbuf, "%s %s the %s...", Goodbye(), plname,
776 (const char *) ((flags.female && urole.name.f) ?
777 urole.name.f : urole.name.m) :
778 (const char *) (flags.female ? "Demigoddess" : "Demigod"));
779 putstr(endwin, 0, pbuf);
780 putstr(endwin, 0, "");
783 if (how == ESCAPED || how == ASCENDED) {
784 register struct monst *mtmp;
785 register struct obj *otmp;
786 register struct val_list *val;
789 for (val = valuables; val->list; val++)
790 for (i = 0; i < val->size; i++) {
791 val->list[i].count = 0L;
793 get_valuables(invent);
795 /* add points for collected valuables */
796 for (val = valuables; val->list; val++)
797 for (i = 0; i < val->size; i++)
798 if (val->list[i].count != 0L)
799 u.urexp += val->list[i].count
800 * (long)objects[val->list[i].typ].oc_cost;
802 /* count the points for artifacts */
803 artifact_score(invent, TRUE, endwin);
806 viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */
808 if (!done_stopprint) Strcpy(pbuf, "You");
812 Sprintf(eos(pbuf), " and %s", mon_nam(mtmp));
814 u.urexp += mtmp->mhp;
817 if (!done_stopprint) putstr(endwin, 0, pbuf);
820 if (!done_stopprint) Strcat(pbuf, " ");
822 if (!done_stopprint) {
823 Sprintf(eos(pbuf), "%s with %ld point%s,",
824 how==ASCENDED ? "went to your reward" :
825 "escaped from the dungeon",
826 u.urexp, plur(u.urexp));
827 putstr(endwin, 0, pbuf);
831 artifact_score(invent, FALSE, endwin); /* list artifacts */
833 /* list valuables here */
834 for (val = valuables; val->list; val++) {
835 sort_valuables(val->list, val->size);
836 for (i = 0; i < val->size && !done_stopprint; i++) {
837 int typ = val->list[i].typ;
838 long count = val->list[i].count;
840 if (count == 0L) continue;
841 if (objects[typ].oc_class != GEM_CLASS || typ <= LAST_GEM) {
842 otmp = mksobj(typ, FALSE, FALSE);
843 makeknown(otmp->otyp);
844 otmp->known = 1; /* for fake amulets */
845 otmp->dknown = 1; /* seen it (blindness fix) */
848 Sprintf(pbuf, "%8ld %s (worth %ld %s),",
850 count * (long)objects[typ].oc_cost, currency(2L));
851 obfree(otmp, (struct obj *)0);
854 "%8ld worthless piece%s of colored glass,",
857 putstr(endwin, 0, pbuf);
861 } else if (!done_stopprint) {
862 /* did not escape or ascend */
863 if (u.uz.dnum == 0 && u.uz.dlevel <= 0) {
864 /* level teleported out of the dungeon; `how' is DIED,
865 due to falling or to "arriving at heaven prematurely" */
866 Sprintf(pbuf, "You %s beyond the confines of the dungeon",
867 (u.uz.dlevel < 0) ? "passed away" : ends[how]);
869 /* more conventional demise */
870 const char *where = dungeons[u.uz.dnum].dname;
872 if (Is_astralevel(&u.uz)) where = "The Astral Plane";
873 Sprintf(pbuf, "You %s in %s", ends[how], where);
874 if (!In_endgame(&u.uz) && !Is_knox(&u.uz))
875 Sprintf(eos(pbuf), " on dungeon level %d",
876 In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz));
879 Sprintf(eos(pbuf), " with %ld point%s,",
880 u.urexp, plur(u.urexp));
881 putstr(endwin, 0, pbuf);
884 if (!done_stopprint) {
885 Sprintf(pbuf, "and %ld piece%s of gold, after %ld move%s.",
886 umoney, plur(umoney), moves, plur(moves));
887 putstr(endwin, 0, pbuf);
889 if (!done_stopprint) {
891 "You were level %d with a maximum of %d hit point%s when you %s.",
892 u.ulevel, u.uhpmax, plur(u.uhpmax), ends[how]);
893 putstr(endwin, 0, pbuf);
894 putstr(endwin, 0, "");
897 display_nhwindow(endwin, TRUE);
898 if (endwin != WIN_ERR)
899 destroy_nhwindow(endwin);
901 /* "So when I die, the first thing I will see in Heaven is a
903 if (flags.toptenwin) {
906 exit_nhwindows((char *)0);
909 exit_nhwindows((char *)0);
913 if(done_stopprint) { raw_print(""); raw_print(""); }
914 terminate(EXIT_SUCCESS);
919 container_contents(list, identified, all_containers)
921 boolean identified, all_containers;
923 register struct obj *box, *obj;
926 for (box = list; box; box = box->nobj) {
927 if (Is_container(box) || box->otyp == STATUE) {
928 if (box->otyp == BAG_OF_TRICKS) {
929 continue; /* wrong type of container */
930 } else if (box->cobj) {
931 winid tmpwin = create_nhwindow(NHW_MENU);
932 Sprintf(buf, "Contents of %s:", the(xname(box)));
933 putstr(tmpwin, 0, buf);
934 putstr(tmpwin, 0, "");
935 for (obj = box->cobj; obj; obj = obj->nobj) {
937 makeknown(obj->otyp);
938 obj->known = obj->bknown =
939 obj->dknown = obj->rknown = 1;
941 putstr(tmpwin, 0, doname(obj));
943 display_nhwindow(tmpwin, TRUE);
944 destroy_nhwindow(tmpwin);
946 container_contents(box->cobj, identified, TRUE);
948 pline("%s empty.", Tobjnam(box, "are"));
949 display_nhwindow(WIN_MESSAGE, FALSE);
958 /* should be called with either EXIT_SUCCESS or EXIT_FAILURE */
964 getreturn("to exit");
966 /* don't bother to try to release memory if we're in panic mode, to
967 avoid trouble in case that happens to be due to memory problems */
968 if (!program_state.panicking) {
973 nethack_exit(status);
977 list_vanquished(defquery, ask)
982 int ntypes = 0, max_lev = 0, nkilled;
983 long total_killed = 0L;
988 /* get totals first */
989 for (i = LOW_PM; i < NUMMONS; i++) {
990 if (mvitals[i].died) ntypes++;
991 total_killed += (long)mvitals[i].died;
992 if (mons[i].mlevel > max_lev) max_lev = mons[i].mlevel;
995 /* vanquished creatures list;
996 * includes all dead monsters, not just those killed by the player
999 c = ask ? yn_function("Do you want an account of creatures vanquished?",
1000 ynqchars, defquery) : defquery;
1001 if (c == 'q') done_stopprint++;
1003 klwin = create_nhwindow(NHW_MENU);
1004 putstr(klwin, 0, "Vanquished creatures:");
1005 putstr(klwin, 0, "");
1007 /* countdown by monster "toughness" */
1008 for (lev = max_lev; lev >= 0; lev--)
1009 for (i = LOW_PM; i < NUMMONS; i++)
1010 if (mons[i].mlevel == lev && (nkilled = mvitals[i].died) > 0) {
1011 if ((mons[i].geno & G_UNIQ) && i != PM_HIGH_PRIEST) {
1012 Sprintf(buf, "%s%s",
1013 !type_is_pname(&mons[i]) ? "The " : "",
1017 case 2: Sprintf(eos(buf)," (twice)"); break;
1018 case 3: Sprintf(eos(buf)," (thrice)"); break;
1019 default: Sprintf(eos(buf)," (%d time%s)",
1020 nkilled, plur(nkilled));
1025 /* trolls or undead might have come back,
1026 but we don't keep track of that */
1028 Strcpy(buf, an(mons[i].mname));
1030 Sprintf(buf, "%d %s",
1031 nkilled, makeplural(mons[i].mname));
1033 putstr(klwin, 0, buf);
1036 * if (Hallucination)
1037 * putstr(klwin, 0, "and a partridge in a pear tree");
1040 putstr(klwin, 0, "");
1041 Sprintf(buf, "%ld creatures vanquished.", total_killed);
1042 putstr(klwin, 0, buf);
1044 display_nhwindow(klwin, TRUE);
1045 destroy_nhwindow(klwin);
1050 /* number of monster species which have been genocided */
1056 for (i = LOW_PM; i < NUMMONS; ++i)
1057 if (mvitals[i].mvflags & G_GENOD) ++n;
1063 list_genocided(defquery, ask)
1073 ngenocided = num_genocides();
1075 /* genocided species list */
1076 if (ngenocided != 0) {
1077 c = ask ? yn_function("Do you want a list of species genocided?",
1078 ynqchars, defquery) : defquery;
1079 if (c == 'q') done_stopprint++;
1081 klwin = create_nhwindow(NHW_MENU);
1082 putstr(klwin, 0, "Genocided species:");
1083 putstr(klwin, 0, "");
1085 for (i = LOW_PM; i < NUMMONS; i++)
1086 if (mvitals[i].mvflags & G_GENOD) {
1087 if ((mons[i].geno & G_UNIQ) && i != PM_HIGH_PRIEST)
1088 Sprintf(buf, "%s%s",
1089 !type_is_pname(&mons[i]) ? "" : "the ",
1092 Strcpy(buf, makeplural(mons[i].mname));
1093 putstr(klwin, 0, buf);
1096 putstr(klwin, 0, "");
1097 Sprintf(buf, "%d species genocided.", ngenocided);
1098 putstr(klwin, 0, buf);
1100 display_nhwindow(klwin, TRUE);
1101 destroy_nhwindow(klwin);