Source:NetHack 3.3.0/end.c

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