Source:NetHack 3.2.0/end.c

From NetHackWiki
Revision as of 08:31, 4 March 2008 by Kernigh bot (talk | contribs) (NetHack 3.2.0/end.c moved to Source:NetHack 3.2.0/end.c: Robot: moved page)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Below is the full text to end.c from the source code of NetHack 3.2.0. To link to a particular line, write [[NetHack 3.2.0/end.c#line123]], for example.

Warning! This is the source code from an old release. For the latest release, see Source code

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

1.    /*	SCCS Id: @(#)end.c	3.2	95/11/29	*/
2.    /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3.    /* NetHack may be freely redistributed.  See license for details. */
4.    
5.    #define NEED_VARARGS	/* comment line for pre-compiled headers */
6.    
7.    #include "hack.h"
8.    #include "eshk.h"
9.    #ifndef NO_SIGNAL
10.   #include <signal.h>
11.   #endif
12.   #include "dlb.h"
13.   
14.   STATIC_PTR void FDECL(done_intr, (int));
15.   static void FDECL(disclose,(int,BOOLEAN_P));
16.   static void FDECL(get_valuables, (struct obj *));
17.   static void FDECL(sort_valuables, (struct obj **,int));
18.   static void FDECL(savelife, (int));
19.   static void NDECL(list_vanquished);
20.   static void NDECL(list_genocided);
21.   #if defined(UNIX) || defined(VMS)
22.   static void FDECL(done_hangup, (int));
23.   #endif
24.   
25.   
26.   #define done_stopprint program_state.stopprint
27.   
28.   #ifdef AMIGA
29.   void NDECL(clear_icon);
30.   # define NH_abort()	Abort(0)
31.   #else
32.   # ifdef SYSV
33.   # define NH_abort()	(void) abort()
34.   # else
35.   # define NH_abort()	abort()
36.   # endif
37.   #endif
38.   
39.   /*
40.    * The order of these needs to match the macros in hack.h.
41.    */
42.   static NEARDATA const char *deaths[] = {		/* the array of death */
43.   	"died", "choked", "poisoned", "starvation", "drowning",
44.   	"burning", "dissolving under the heat and pressure",
45.   	"crushed", "turned to stone", "genocided",
46.   	"panic", "trickery",
47.   	"quit", "escaped", "ascended"
48.   };
49.   
50.   static NEARDATA const char *ends[] = {		/* "when you..." */
51.   	"died", "choked", "were poisoned", "starved", "drowned",
52.   	"burned", "dissolved in the lava",
53.   	"were crushed", "turned to stone", "were genocided",
54.   	"panicked", "were tricked",
55.   	"quit", "escaped", "ascended"
56.   };
57.   
58.   	/* these probably ought to be generated by makedefs, like LAST_GEM */
59.   #define FIRST_GEM    DILITHIUM_CRYSTAL
60.   #define FIRST_AMULET AMULET_OF_ESP
61.   #define LAST_AMULET  AMULET_OF_YENDOR
62.   
63.   static struct obj *gems[LAST_GEM+1 - FIRST_GEM + 1],	/* 1 extra for glass */
64.   		  *amulets[LAST_AMULET+1 - FIRST_AMULET];
65.   
66.   static struct val_list { struct obj **list; int size; } valuables[] = {
67.   	{ gems,    sizeof gems / sizeof *gems },
68.   	{ amulets, sizeof amulets / sizeof *amulets },
69.   	{ 0, 0 }
70.   };
71.   
72.   /*ARGSUSED*/
73.   void
74.   done1(sig_unused)   /* called as signal() handler, so sent at least one arg */
75.   int sig_unused;
76.   {
77.   #ifndef NO_SIGNAL
78.   	(void) signal(SIGINT,SIG_IGN);
79.   #endif
80.   	if(flags.ignintr) {
81.   #ifndef NO_SIGNAL
82.   		(void) signal(SIGINT, (SIG_RET_TYPE) done1);
83.   #endif
84.   		clear_nhwindow(WIN_MESSAGE);
85.   		curs_on_u();
86.   		wait_synch();
87.   		if(multi > 0) nomul(0);
88.   	} else {
89.   		(void)done2();
90.   	}
91.   }
92.   
93.   int
94.   done2()
95.   {
96.   	if(yn("Really quit?") == 'n') {
97.   #ifndef NO_SIGNAL
98.   		(void) signal(SIGINT, (SIG_RET_TYPE) done1);
99.   #endif
100.  		clear_nhwindow(WIN_MESSAGE);
101.  		curs_on_u();
102.  		wait_synch();
103.  		if(multi > 0) nomul(0);
104.  		if(multi == 0) {
105.  		    u.uinvulnerable = FALSE;	/* avoid ctrl-C bug -dlc */
106.  		    u.usleep = 0;
107.  		}
108.  		return 0;
109.  	}
110.  #if defined(WIZARD) && (defined(UNIX) || defined(VMS) || defined(LATTICE))
111.  	if(wizard) {
112.  	    int c;
113.  # ifdef VMS
114.  	    const char *tmp = "Enter debugger?";
115.  # else
116.  #  ifdef LATTICE
117.  	    const char *tmp = "Create SnapShot?";
118.  #  else
119.  	    const char *tmp = "Dump core?";
120.  #  endif
121.  # endif
122.  	    if ((c = ynq(tmp)) == 'y') {
123.  		(void) signal(SIGINT, (SIG_RET_TYPE) done1);
124.  		exit_nhwindows((char *)0);
125.  		NH_abort();
126.  	    } else if (c == 'q') done_stopprint++;
127.  	}
128.  #endif
129.  #ifndef LINT
130.  	done(QUIT);
131.  #endif
132.  	return 0;
133.  }
134.  
135.  /*ARGSUSED*/
136.  STATIC_PTR void
137.  done_intr(sig_unused) /* called as signal() handler, so sent at least one arg */
138.  int sig_unused;
139.  {
140.  	done_stopprint++;
141.  #ifndef NO_SIGNAL
142.  	(void) signal(SIGINT, SIG_IGN);
143.  # if defined(UNIX) || defined(VMS)
144.  	(void) signal(SIGQUIT, SIG_IGN);
145.  # endif
146.  #endif /* NO_SIGNAL */
147.  	return;
148.  }
149.  
150.  #if defined(UNIX) || defined(VMS)
151.  static void
152.  done_hangup(sig)	/* signal() handler */
153.  int sig;
154.  {
155.  	program_state.done_hup++;
156.  	(void)signal(SIGHUP, SIG_IGN);
157.  	done_intr(sig);
158.  	return;
159.  }
160.  #endif
161.  
162.  void
163.  done_in_by(mtmp)
164.  register struct monst *mtmp;
165.  {
166.  	char buf[BUFSZ];
167.  	boolean distorted = (boolean)(Hallucination && canspotmon(mtmp));
168.  
169.  	You("die...");
170.  	mark_synch();	/* flush buffered screen output */
171.  	buf[0] = '\0';
172.  	if ((mtmp->data->geno & G_UNIQ) != 0) {
173.  	    if (!type_is_pname(mtmp->data))
174.  		Strcat(buf, "the ");
175.  	    killer_format = KILLED_BY;
176.  	}
177.  	if (mtmp->minvis && !(mtmp->ispriest || mtmp->isminion))
178.  		Strcat(buf, "invisible ");
179.  	if (distorted)
180.  		Strcat(buf, "hallucinogen-distorted ");
181.  
182.  	if(mtmp->data == &mons[PM_GHOST]) {
183.  		register char *gn = (char *) mtmp->mextra;
184.  		if (!distorted && !mtmp->minvis && *gn) {
185.  			Strcat(buf, "the ");
186.  			killer_format = KILLED_BY;
187.  		}
188.  		Sprintf(eos(buf), (*gn ? "ghost of %s" : "ghost%s"), gn);
189.  	} else if(mtmp->isshk) {
190.  		Sprintf(eos(buf), "%s %s, the shopkeeper",
191.  			(mtmp->female ? "Ms." : "Mr."), shkname(mtmp));
192.  		killer_format = KILLED_BY;
193.  	} else if (mtmp->ispriest || mtmp->isminion) {
194.  		killer = priestname(mtmp);
195.  		if (!strncmp(killer, "the ", 4)) Strcat(buf, killer+4);
196.  		else Strcat(buf, killer);
197.  	} else Strcat(buf, mtmp->data->mname);
198.  	if (mtmp->mnamelth) Sprintf(eos(buf), " called %s", NAME(mtmp));
199.  	killer = buf;
200.  	if (mtmp->data->mlet == S_WRAITH)
201.  		u.ugrave_arise = PM_WRAITH;
202.  	else if (mtmp->data->mlet == S_MUMMY)
203.  		u.ugrave_arise = Role_is('E') ? PM_ELF_MUMMY : PM_HUMAN_MUMMY;
204.  	else if (mtmp->data->mlet == S_VAMPIRE && !Role_is('E'))
205.  		u.ugrave_arise = PM_VAMPIRE;
206.  	if (u.ugrave_arise >= LOW_PM &&
207.  				(mvitals[u.ugrave_arise].mvflags & G_GENOD))
208.  		u.ugrave_arise = NON_PM;
209.  	if (mtmp->data->mlet == S_COCKATRICE)
210.  		done(STONING);
211.  	else
212.  		done(DIED);
213.  	return;
214.  }
215.  
216.  /*VARARGS1*/
217.  void
218.  panic VA_DECL(const char *, str)
219.  	VA_START(str);
220.  	VA_INIT(str, char *);
221.  
222.  	if (program_state.panicking++)
223.  	    NH_abort();	/* avoid loops - this should never happen*/
224.  
225.  	if (flags.window_inited) {
226.  	    raw_print("\r\nOops...");
227.  	    wait_synch();	/* make sure all pending output gets flushed */
228.  	    exit_nhwindows((char *)0);
229.  	    flags.window_inited = 0; /* they're gone; force raw_print()ing */
230.  	}
231.  
232.  	raw_print(!program_state.something_worth_saving ?
233.  		  "Program initialization has failed." :
234.  		  "Suddenly, the dungeon collapses.");
235.  #if defined(WIZARD) && !defined(MICRO)
236.  	if (!wizard)
237.  	    raw_printf("Report error to \"%s\"%s.",
238.  # ifdef WIZARD_NAME	/*(KR1ED)*/
239.  			WIZARD_NAME,
240.  # else
241.  			WIZARD,
242.  # endif
243.  			!program_state.something_worth_saving ? "" :
244.  			" and it may be possible to rebuild.");
245.  	if (program_state.something_worth_saving) {
246.  	    set_error_savefile();
247.  	    (void) dosave0();
248.  	}
249.  #endif
250.  	{
251.  	    char buf[BUFSZ];
252.  	    Vsprintf(buf,str,VA_ARGS);
253.  	    raw_print(buf);
254.  	}
255.  #if defined(WIZARD) && (defined(UNIX) || defined(VMS) || defined(LATTICE))
256.  	if (wizard)
257.  	    NH_abort();	/* generate core dump */
258.  #endif
259.  	VA_END();
260.  	done(PANICKED);
261.  }
262.  
263.  static void
264.  disclose(how,taken)
265.  int how;
266.  boolean taken;
267.  {
268.  	char	c;
269.  	char	qbuf[QBUFSZ];
270.  
271.  	if (invent && !done_stopprint &&
272.  		(!flags.end_disclose[0] || index(flags.end_disclose, 'i'))) {
273.  	    if(taken)
274.  		Sprintf(qbuf,"Do you want to see what you had when you %s?",
275.  			(how == QUIT) ? "quit" : "died");
276.  	    else
277.  		Strcpy(qbuf,"Do you want your possessions identified?");
278.  	    if ((c = yn_function(qbuf, ynqchars, 'y')) == 'y') {
279.  	    /* New dump format by maartenj@cs.vu.nl */
280.  		struct obj *obj;
281.  
282.  		for (obj = invent; obj; obj = obj->nobj) {
283.  		    makeknown(obj->otyp);
284.  		    obj->known = obj->bknown = obj->dknown = obj->rknown = 1;
285.  		}
286.  		(void) display_inventory((char *)0, TRUE);
287.  		container_contents(invent, TRUE, TRUE);
288.  	    }
289.  	    if (c == 'q')  done_stopprint++;
290.  	}
291.  
292.  	if (!done_stopprint &&
293.  		(!flags.end_disclose[0] || index(flags.end_disclose, 'a'))) {
294.  	    c = yn_function("Do you want to see your attributes?",ynqchars,'y');
295.  	    if (c == 'y') enlightenment(how >= PANICKED ? 1 : 2); /* final */
296.  	    if (c == 'q') done_stopprint++;
297.  	}
298.  
299.  	if (!done_stopprint &&
300.  		(!flags.end_disclose[0] || index(flags.end_disclose, 'v'))) {
301.  	    list_vanquished();
302.  	}
303.  
304.  	if (!done_stopprint &&
305.  		(!flags.end_disclose[0] || index(flags.end_disclose, 'g'))) {
306.  	    list_genocided();
307.  	}
308.  }
309.  
310.  /* try to get the player back in a viable state after being killed */
311.  static void
312.  savelife(how)
313.  int how;
314.  {
315.  	u.uswldtim = 0;
316.  	u.uhp = u.uhpmax;
317.  	if (u.uhunger < 500) {
318.  	    u.uhunger = 500;
319.  	    newuhs(FALSE);
320.  	}
321.  	if (how == CHOKING) init_uhunger();
322.  	nomovemsg = "You survived that attempt on your life.";
323.  	flags.move = 0;
324.  	if(multi > 0) multi = 0; else multi = -1;
325.  	if(u.utrap && u.utraptype == TT_LAVA) u.utrap = 0;
326.  	flags.botl = 1;
327.  	u.ugrave_arise = NON_PM;
328.  	curs_on_u();
329.  }
330.  
331.  /*
332.   *  Get valuables from the given list. NOTE: The list is destroyed as it is
333.   *  processed, so don't expect to use it again!  [Revised code: the list
334.   *  remains intact, but object quanties for some elements are altered.]
335.   */
336.  static void
337.  get_valuables(list)
338.  struct obj *list;	/* inventory or container contents */
339.  {
340.      register struct obj *obj;
341.      register int i;
342.  
343.      /* find amulets and gems; artifact amulets are treated as ordinary ones */
344.      for (obj = list; obj; obj = obj->nobj)
345.  	if (Has_contents(obj)) {
346.  	    get_valuables(obj->cobj);
347.  	} else if (obj->oclass == AMULET_CLASS) {
348.  	    i = obj->otyp - FIRST_AMULET;
349.  	    if (!amulets[i]) amulets[i] = obj;
350.  	    else amulets[i]->quan += obj->quan;	/*(always adds one)*/
351.  	} else if (obj->oclass == GEM_CLASS && obj->otyp < LUCKSTONE) {
352.  	    i = min(obj->otyp, LAST_GEM + 1) - FIRST_GEM;
353.  	    if (!gems[i]) gems[i] = obj;
354.  	    else gems[i]->quan += obj->quan;
355.  	}
356.      return;
357.  }
358.  
359.  /*
360.   *  Sort collected valuables, most frequent to least.  We could just
361.   *  as easily use qsort, but we don't care about efficiency here.
362.   */
363.  static void
364.  sort_valuables(list, size)
365.  struct obj *list[];
366.  int size;		/* max value is less than 20 */
367.  {
368.      register int i, j;
369.      register struct obj *obj;
370.  
371.      /* move greater quantities to the front of the list */
372.      for (i = 1; i < size; i++) {
373.  	if ((obj = list[i]) == 0) continue;	/* empty slot */
374.  	for (j = i; j > 0; --j)
375.  	    if (list[j-1] && list[j-1]->quan >= obj->quan) break;
376.  	    else list[j] = list[j-1];
377.  	list[j] = obj;
378.      }
379.      return;
380.  }
381.  
382.  /* Be careful not to call panic from here! */
383.  void
384.  done(how)
385.  int how;
386.  {
387.  	boolean taken;
388.  	char kilbuf[BUFSZ], pbuf[BUFSZ];
389.  	winid endwin = WIN_ERR;
390.  	boolean bones_ok, have_windows = flags.window_inited;
391.  
392.  	/* kilbuf: used to copy killer in case it comes from something like
393.  	 *	xname(), which would otherwise get overwritten when we call
394.  	 *	xname() when listing possessions
395.  	 * pbuf: holds Sprintf'd output for raw_print and putstr
396.  	 */
397.  	if (how == ASCENDED)
398.  		killer_format = NO_KILLER_PREFIX;
399.  	/* Avoid killed by "a" burning or "a" starvation */
400.  	if (!killer && (how == STARVING || how == BURNING))
401.  		killer_format = KILLED_BY;
402.  	Strcpy(kilbuf, (!killer || how >= PANICKED ? deaths[how] : killer));
403.  	killer = kilbuf;
404.  #ifdef WIZARD
405.  	if (wizard && how == TRICKED) {
406.  		You("are a very tricky wizard, it seems.");
407.  		return;
408.  	}
409.  #endif
410.  	if (how < PANICKED) u.umortality++;
411.  	if (Lifesaved && how <= GENOCIDED) {
412.  		pline("But wait...");
413.  		makeknown(AMULET_OF_LIFE_SAVING);
414.  		Your("medallion %s!",
415.  		      !Blind ? "begins to glow" : "feels warm");
416.  		if (how == CHOKING) You("vomit ...");
417.  		You_feel("much better!");
418.  		pline_The("medallion crumbles to dust!");
419.  		useup(uamul);
420.  
421.  		(void) adjattrib(A_CON, -1, TRUE);
422.  		if(u.uhpmax <= 0) u.uhpmax = 10;	/* arbitrary */
423.  		savelife(how);
424.  		if (how == GENOCIDED)
425.  			pline("Unfortunately you are still genocided...");
426.  		else {
427.  			killer = 0;
428.  			killer_format = 0;
429.  			return;
430.  		}
431.  	}
432.  	if ((wizard || discover) && how <= GENOCIDED) {
433.  		if(yn("Die?") == 'y') goto die;
434.  		pline("OK, so you don't %s.",
435.  			(how == CHOKING) ? "choke" : "die");
436.  		if(u.uhpmax <= 0) u.uhpmax = u.ulevel * 8;	/* arbitrary */
437.  		savelife(how);
438.  		killer = 0;
439.  		killer_format = 0;
440.  		return;
441.  	}
442.  
443.  	/* Sometimes you die on the first move.  Life's not fair.
444.  	 * On those rare occasions you get hosed immediately, go out
445.  	 * smiling... :-)  -3.
446.  	 */
447.  	if (moves <= 1 && how < PANICKED)
448.  	    /* You die... --More-- */
449.  	    pline("Do not pass go.  Do not collect 200 zorkmids.");
450.  
451.  die:
452.  	if (have_windows) wait_synch();	/* flush screen output */
453.  #ifndef NO_SIGNAL
454.  	(void) signal(SIGINT, (SIG_RET_TYPE) done_intr);
455.  # if defined(UNIX) || defined(VMS)
456.  	(void) signal(SIGQUIT, (SIG_RET_TYPE) done_intr);
457.  	(void) signal(SIGHUP, (SIG_RET_TYPE) done_hangup);
458.  # endif
459.  #endif /* NO_SIGNAL */
460.  
461.  	bones_ok = (how < GENOCIDED) && can_make_bones();
462.  
463.  	if (bones_ok && u.ugrave_arise < LOW_PM) {
464.  	    if (how == BURNING)		/* corpse gets burnt up too */
465.  		u.ugrave_arise = (NON_PM - 2);	/* leave no corpse */
466.  	    else if (how == STONING)
467.  		u.ugrave_arise = (NON_PM - 1);	/* statue instead of corpse */
468.  	    else if (u.ugrave_arise == NON_PM)
469.  		(void) mk_named_object(CORPSE, Upolyd ? uasmon : player_mon(),
470.  				       u.ux, u.uy, plname);
471.  	}
472.  
473.  	if (how == QUIT) {
474.  		killer_format = NO_KILLER_PREFIX;
475.  		if (u.uhp < 1) {
476.  			how = DIED;
477.  /* note that killer is pointing at kilbuf */
478.  			Strcpy(kilbuf, "quit while already on Charon's boat");
479.  		}
480.  	}
481.  	if (how == ESCAPED || how == PANICKED)
482.  		killer_format = NO_KILLER_PREFIX;
483.  
484.  	if (how != PANICKED) {
485.  	    /* these affect score and/or bones, but avoid them during panic */
486.  	    taken = paybill(how != QUIT);
487.  	    paygd();
488.  	    clearpriests();
489.  	} else	taken = FALSE;	/* lint; assert( !bones_ok ); */
490.  
491.  	clearlocks();
492.  #ifdef AMIGA
493.  	clear_icon();
494.  #endif
495.  	if (have_windows) display_nhwindow(WIN_MESSAGE, FALSE);
496.  
497.  	if (strcmp(flags.end_disclose, "none") && how != PANICKED)
498.  		disclose(how, taken);
499.  	/* finish_paybill should be called after disclosure but before bones */
500.  	if (bones_ok && taken) finish_paybill();
501.  
502.  	/* calculate score, before creating bones [container gold] */
503.  	{
504.  	    long tmp;
505.  	    int deepest = deepest_lev_reached(FALSE);
506.  
507.  	    u.ugold += hidden_gold();	/* accumulate gold from containers */
508.  	    tmp = u.ugold - u.ugold0;
509.  	    if (tmp < 0L)
510.  		tmp = 0L;
511.  	    if (how < PANICKED)
512.  		tmp -= tmp / 10L;
513.  	    u.urexp += tmp;
514.  	    u.urexp += 50L * (long)(deepest - 1);
515.  	    if (deepest > 20)
516.  		u.urexp += 1000L * (long)((deepest > 30) ? 10 : deepest - 20);
517.  	    if (how == ASCENDED) u.urexp *= 2L;
518.  	}
519.  
520.  	if (bones_ok) {
521.  #ifdef WIZARD
522.  	    if (!wizard || yn("Save bones?") == 'y')
523.  #endif
524.  		savebones();
525.  	}
526.  
527.  	/* clean up unneeded windows */
528.  	if (have_windows) {
529.  	    destroy_nhwindow(WIN_MAP);
530.  	    destroy_nhwindow(WIN_STATUS);
531.  	    destroy_nhwindow(WIN_MESSAGE);
532.  
533.  	    if(!done_stopprint || flags.tombstone)
534.  		endwin = create_nhwindow(NHW_TEXT);
535.  
536.  	    if(how < GENOCIDED && flags.tombstone) outrip(endwin, how);
537.  	} else
538.  	    done_stopprint = 1; /* just avoid any more output */
539.  
540.  /* changing kilbuf really changes killer. we do it this way because
541.     killer is declared a (const char *)
542.  */
543.  	if (u.uhave.amulet) Strcat(kilbuf, " (with the Amulet)");
544.  	if (!done_stopprint) {
545.  	    Sprintf(pbuf, "%s %s the %s...",
546.  		   Role_is('S') ? "Sayonara" :
547.  #ifdef TOURIST
548.  		   Role_is('T') ? "Aloha" :
549.  #endif
550.  			"Goodbye", plname,
551.  		   how != ASCENDED ? (const char *) pl_character :
552.  		   (const char *) (flags.female ? "Demigoddess" : "Demigod"));
553.  	    putstr(endwin, 0, pbuf);
554.  	    putstr(endwin, 0, "");
555.  	}
556.  
557.  	if (how == ESCAPED || how == ASCENDED) {
558.  	    register struct monst *mtmp;
559.  	    register struct obj *otmp;
560.  	    register struct val_list *val;
561.  	    register int i;
562.  
563.  	    /*
564.  	     * Collecting valuables renders `invent' invalid, but from
565.  	     * this point on, it won't be used again.
566.  	     */
567.  	    for (val = valuables; val->list; val++)
568.  		for (i = 0; i < val->size; i++) val->list[i] = (struct obj *)0;
569.  	    get_valuables(invent);
570.  
571.  	    /* add points for collected valuables */
572.  	    for (val = valuables; val->list; val++)
573.  		for (i = 0; i < val->size; i++)
574.  		    if ((otmp = val->list[i]) != 0)
575.  			u.urexp += otmp->quan
576.  				  * (long)objects[otmp->otyp].oc_cost;
577.  
578.  	    keepdogs(TRUE);
579.  	    viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */
580.  	    mtmp = mydogs;
581.  	    if (!done_stopprint) Strcpy(pbuf, "You");
582.  	    if (mtmp) {
583.  		while (mtmp) {
584.  		    if (!done_stopprint)
585.  			Sprintf(eos(pbuf), " and %s", mon_nam(mtmp));
586.  		    if (mtmp->mtame)
587.  			u.urexp += mtmp->mhp;
588.  		    mtmp = mtmp->nmon;
589.  		}
590.  		if (!done_stopprint) putstr(endwin, 0, pbuf);
591.  		pbuf[0] = '\0';
592.  	    } else {
593.  		if (!done_stopprint) Strcat(pbuf, " ");
594.  	    }
595.  	    if (!done_stopprint) {
596.  		Sprintf(eos(pbuf), "%s with %ld point%s,",
597.  			how==ASCENDED ? "went to your reward" :
598.  					"escaped from the dungeon",
599.  			u.urexp, plur(u.urexp));
600.  		putstr(endwin, 0, pbuf);
601.  	    }
602.  
603.  	    /* list valuables here */
604.  	    for (val = valuables; val->list; val++) {
605.  		sort_valuables(val->list, val->size);
606.  		for (i = 0; i < val->size && !done_stopprint; i++) {
607.  		    if ((otmp = val->list[i]) == 0) continue;
608.  		    if (otmp->oclass != GEM_CLASS || otmp->otyp <= LAST_GEM) {
609.  			makeknown(otmp->otyp);
610.  			otmp->known = 1;	/* for fake amulets */
611.  			otmp->onamelth = 0;
612.  			Sprintf(pbuf, "%8ld %s (worth %ld zorkmids),",
613.  				otmp->quan, xname(otmp),
614.  				otmp->quan * (long)objects[otmp->otyp].oc_cost);
615.  		    } else {
616.  			Sprintf(pbuf,
617.  				"%8ld worthless piece%s of colored glass,",
618.  				otmp->quan, plur(otmp->quan));
619.  		    }
620.  		    putstr(endwin, 0, pbuf);
621.  		}
622.  	    }
623.  
624.  	} else if (!done_stopprint) {
625.  	    /* did not escape or ascend */
626.  	    const char *where = dungeons[u.uz.dnum].dname;
627.  	    if (Is_astralevel(&u.uz)) where = "The Astral Plane";
628.  	    Sprintf(pbuf, "You %s in %s", ends[how], where);
629.  	    if (!In_endgame(&u.uz) && !Is_knox(&u.uz))
630.  		Sprintf(eos(pbuf), " on dungeon level %d",
631.  			In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz));
632.  	    Sprintf(eos(pbuf), " with %ld point%s,",
633.  		    u.urexp, plur(u.urexp));
634.  	    putstr(endwin, 0, pbuf);
635.  	}
636.  
637.  	if (!done_stopprint) {
638.  	    Sprintf(pbuf, "and %ld piece%s of gold, after %ld move%s.",
639.  		    u.ugold, plur(u.ugold), moves, plur(moves));
640.  	    putstr(endwin, 0, pbuf);
641.  	}
642.  	if (!done_stopprint) {
643.  	    Sprintf(pbuf,
644.  	     "You were level %d with a maximum of %d hit point%s when you %s.",
645.  		    u.ulevel, u.uhpmax, plur(u.uhpmax), ends[how]);
646.  	    putstr(endwin, 0, pbuf);
647.  	    putstr(endwin, 0, "");
648.  	}
649.  	if (!done_stopprint)
650.  	    display_nhwindow(endwin, TRUE);
651.  	if (endwin != WIN_ERR)
652.  	    destroy_nhwindow(endwin);
653.  
654.  	/* "So when I die, the first thing I will see in Heaven is a
655.  	 * score list?" */
656.  	if (flags.toptenwin) {
657.  	    topten(how);
658.  	    if (have_windows)
659.  		exit_nhwindows((char *)0);
660.  	} else {
661.  	    if (have_windows)
662.  		exit_nhwindows((char *)0);
663.  	    topten(how);
664.  	}
665.  
666.  	if(done_stopprint) { raw_print(""); raw_print(""); }
667.  	terminate(EXIT_SUCCESS);
668.  }
669.  
670.  
671.  void
672.  container_contents(list, identified, all_containers)
673.  struct obj *list;
674.  boolean identified, all_containers;
675.  {
676.  	register struct obj *box, *obj;
677.  	char buf[BUFSZ];
678.  
679.  	for (box = list; box; box = box->nobj) {
680.  	    if (Is_container(box) && box->otyp != BAG_OF_TRICKS) {
681.  		if (box->cobj) {
682.  		    winid tmpwin = create_nhwindow(NHW_MENU);
683.  		    Sprintf(buf, "Contents of %s:", the(xname(box)));
684.  		    putstr(tmpwin, 0, buf);
685.  		    putstr(tmpwin, 0, "");
686.  		    for (obj = box->cobj; obj; obj = obj->nobj) {
687.  			if (identified) {
688.  			    makeknown(obj->otyp);
689.  			    obj->known = obj->bknown =
690.  			    obj->dknown = obj->rknown = 1;
691.  			}
692.  			putstr(tmpwin, 0, doname(obj));
693.  		    }
694.  		    display_nhwindow(tmpwin, TRUE);
695.  		    destroy_nhwindow(tmpwin);
696.  		    if (all_containers)
697.  			container_contents(box->cobj, identified, TRUE);
698.  		} else {
699.  		    pline("%s is empty.", The(xname(box)));
700.  		    display_nhwindow(WIN_MESSAGE, FALSE);
701.  		}
702.  	    }
703.  	    if (!all_containers)
704.  		break;
705.  	}
706.  }
707.  
708.  
709.  /* should be called with either EXIT_SUCCESS or EXIT_FAILURE */
710.  void
711.  terminate(status)
712.  int status;
713.  {
714.  #ifdef MAC
715.  	getreturn("to exit");
716.  #endif
717.  
718.  	/* don't bother to try to release memory if we're in panic mode, to
719.  	   avoid trouble in case that happens to be due to memory problems */
720.  	if (!program_state.panicking) {
721.  	    freedynamicdata();
722.  	    dlb_cleanup();
723.  	}
724.  
725.  	exit(status);
726.  }
727.  
728.  static void
729.  list_vanquished()
730.  {
731.      register int i, lev;
732.      int ntypes = 0, max_lev = 0, nkilled;
733.      long total_killed = 0L;
734.      char c;
735.      winid klwin;
736.      char buf[BUFSZ];
737.  
738.      /* get totals first */
739.      for (i = LOW_PM; i < NUMMONS; i++) {
740.  	if (mvitals[i].died) ntypes++;
741.  	total_killed += (long)mvitals[i].died;
742.  	if (mons[i].mlevel > max_lev) max_lev = mons[i].mlevel;
743.      }
744.  
745.      /* vanquished creatures list;
746.       * includes all dead monsters, not just those killed by the player
747.       */
748.      if (ntypes != 0) {
749.  	c = yn_function("Do you want an account of creatures vanquished?",
750.  			ynqchars, 'n');
751.  	if (c == 'q') done_stopprint++;
752.  	if (c == 'y') {
753.  	    klwin = create_nhwindow(NHW_MENU);
754.  	    putstr(klwin, 0, "Vanquished creatures:");
755.  	    putstr(klwin, 0, "");
756.  
757.  	    /* countdown by monster "toughness" */
758.  	    for (lev = max_lev; lev >= 0; lev--)
759.  	      for (i = LOW_PM; i < NUMMONS; i++)
760.  		if (mons[i].mlevel == lev && (nkilled = mvitals[i].died) > 0) {
761.  		    if ((mons[i].geno & G_UNIQ) && i != PM_HIGH_PRIEST) {
762.  			Sprintf(buf, "%s%s",
763.  				!type_is_pname(&mons[i]) ? "The " : "",
764.  				mons[i].mname);
765.  			if (nkilled > 1)
766.  			    Sprintf(eos(buf)," (%d time%s)",
767.  				    nkilled, plur(nkilled));
768.  		    } else {
769.  			/* trolls or undead might have come back,
770.  			   but we don't keep track of that */
771.  			if (nkilled == 1)
772.  			    Strcpy(buf, an(mons[i].mname));
773.  			else
774.  			    Sprintf(buf, "%d %s",
775.  				    nkilled, makeplural(mons[i].mname));
776.  		    }
777.  		    putstr(klwin, 0, buf);
778.  		}
779.  	    /*
780.  	     * if (Hallucination)
781.  	     *     putstr(klwin, 0, "and a partridge in a pear tree");
782.  	     */
783.  	    if (ntypes > 1) {
784.  		putstr(klwin, 0, "");
785.  		Sprintf(buf, "%ld creatures vanquished.", total_killed);
786.  		putstr(klwin, 0, buf);
787.  	    }
788.  	    display_nhwindow(klwin, TRUE);
789.  	    destroy_nhwindow(klwin);
790.  	}
791.      }
792.  }
793.  
794.  static void
795.  list_genocided()
796.  {
797.      register int i;
798.      int ngenocided = 0;
799.      char c;
800.      winid klwin;
801.      char buf[BUFSZ];
802.  
803.      /* get totals first */
804.      for (i = LOW_PM; i < NUMMONS; i++) {
805.  	if (mvitals[i].mvflags & G_GENOD) ngenocided++;
806.      }
807.  
808.      /* genocided species list */
809.      if (ngenocided != 0) {
810.  	c = yn_function("Do you want a list of species genocided?",
811.  			ynqchars, 'n');
812.  	if (c == 'q') done_stopprint++;
813.  	if (c == 'y') {
814.  	    klwin = create_nhwindow(NHW_MENU);
815.  	    putstr(klwin, 0, "Genocided species:");
816.  	    putstr(klwin, 0, "");
817.  
818.  	    for (i = LOW_PM; i < NUMMONS; i++)
819.  		if (mvitals[i].mvflags & G_GENOD) {
820.  		    if ((mons[i].geno & G_UNIQ) && i != PM_HIGH_PRIEST)
821.  			Sprintf(buf, "%s%s",
822.  				!type_is_pname(&mons[i]) ? "" : "the ",
823.  				mons[i].mname);
824.  		    else
825.  			Strcpy(buf, makeplural(mons[i].mname));
826.  		    putstr(klwin, 0, buf);
827.  		}
828.  
829.  	    putstr(klwin, 0, "");
830.  	    Sprintf(buf, "%d species genocided.", ngenocided);
831.  	    putstr(klwin, 0, buf);
832.  
833.  	    display_nhwindow(klwin, TRUE);
834.  	    destroy_nhwindow(klwin);
835.  	}
836.      }
837.  }
838.  
839.  /*end.c*/