Source:NetHack 3.1.0/end.c

From NetHackWiki
Jump to navigation Jump to search

Below is the full text to end.c from the source code of NetHack 3.1.0.

Warning! This is the source code from an old release. For newer releases, 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.1	93/01/15	*/
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.   
13.   STATIC_PTR int NDECL(done_intr);
14.   static void FDECL(disclose,(int,BOOLEAN_P));
15.   static struct obj *FDECL(get_valuables, (struct obj *));
16.   static void FDECL(savelife, (int));
17.   
18.   /*
19.    * The order of these needs to match the macros in hack.h.
20.    */
21.   static const char NEARDATA *deaths[] = {		/* the array of death */
22.   	"died", "choked", "poisoned", "starvation", "drowning",
23.   	"burning", "crushed", "turned to stone", "genocided",
24.   	"panic", "trickery",
25.   	"quit", "escaped", "ascended"
26.   };
27.   
28.   static const char NEARDATA *ends[] = {		/* "when you..." */
29.   	"died", "choked", "were poisoned", "starved", "drowned",
30.   	"burned", "were crushed", "turned to stone", "were genocided",
31.   	"panicked", "were tricked",
32.   	"quit", "escaped", "ascended"
33.   };
34.   
35.   int
36.   done1()
37.   {
38.   #ifndef NO_SIGNAL
39.   	(void) signal(SIGINT,SIG_IGN);
40.   #endif
41.   	if(flags.ignintr) {
42.   #ifndef NO_SIGNAL
43.   		(void) signal(SIGINT, (SIG_RET_TYPE) done1);
44.   #endif
45.   		clear_nhwindow(WIN_MESSAGE);
46.   		curs_on_u();
47.   		wait_synch();
48.   		if(multi > 0) nomul(0);
49.   		return 0;
50.   	}
51.   	return done2();
52.   }
53.   
54.   int
55.   done2()
56.   {
57.   	if(yn("Really quit?") == 'n') {
58.   #ifndef NO_SIGNAL
59.   		(void) signal(SIGINT, (SIG_RET_TYPE) done1);
60.   #endif
61.   		clear_nhwindow(WIN_MESSAGE);
62.   		curs_on_u();
63.   		wait_synch();
64.   		if(multi > 0) nomul(0);
65.   		if(multi == 0) {
66.   		    u.uinvulnerable = FALSE;	/* avoid ctrl-C bug -dlc */
67.   		    u.usleep = 0;
68.   		}
69.   		return 0;
70.   	}
71.   #if defined(WIZARD) && (defined(UNIX) || defined(VMS) || defined(LATTICE))
72.   	if(wizard) {
73.   # ifdef VMS
74.   	    const char *tmp = "Enter debugger?";
75.   # else
76.   #  ifdef LATTICE
77.   	    const char *tmp = "Create SnapShot?";
78.   #  else
79.   	    const char *tmp = "Dump core?";
80.   #  endif
81.   # endif
82.   	    if(yn(tmp) == 'y') {
83.   		(void) signal(SIGINT, (SIG_RET_TYPE) done1);
84.   		exit_nhwindows(NULL);
85.   #ifdef AMIGA
86.   		Abort(0);
87.   #else
88.   # ifdef SYSV
89.   		(void)
90.   # endif
91.   		    abort();
92.   #endif
93.   	    }
94.   	}
95.   #endif
96.   #ifndef LINT
97.   	done(QUIT);
98.   #endif
99.   	return 0;
100.  }
101.  
102.  STATIC_PTR
103.  int
104.  done_intr(){
105.  	done_stopprint++;
106.  #ifndef NO_SIGNAL
107.  	(void) signal(SIGINT, SIG_IGN);
108.  # if defined(UNIX) || defined(VMS)
109.  	(void) signal(SIGQUIT, SIG_IGN);
110.  # endif
111.  #endif /* NO_SIGNAL /* */
112.  	return 0;
113.  }
114.  
115.  #if defined(UNIX) || defined(VMS)
116.  static
117.  int
118.  done_hangup(){
119.  	done_hup++;
120.  	(void)signal(SIGHUP, SIG_IGN);
121.  	(void)done_intr();
122.  	return 0;
123.  }
124.  #endif
125.  
126.  void
127.  done_in_by(mtmp)
128.  register struct monst *mtmp;
129.  {
130.  	char buf[BUFSZ];
131.  
132.  	You("die...");
133.  	buf[0] = '\0';
134.  	if (type_is_pname(mtmp->data) || (mtmp->data->geno & G_UNIQ)) {
135.  	     if (!(type_is_pname(mtmp->data) && (mtmp->data->geno & G_UNIQ)))
136.  		Strcat(buf, "the ");
137.  	     killer_format = KILLED_BY;
138.  	}
139.  	if (mtmp->minvis)
140.  		Strcat(buf, "invisible ");
141.  	if (Hallucination)
142.  		Strcat(buf, "hallucinogen-distorted ");
143.  
144.  	if(mtmp->data == &mons[PM_GHOST]) {
145.  		register char *gn = (char *) mtmp->mextra;
146.  		if (!Hallucination && !mtmp->minvis && *gn) {
147.  			Strcat(buf, "the ");
148.  			killer_format = KILLED_BY;
149.  		}
150.  		Sprintf(eos(buf), (*gn ? "ghost of %s" : "ghost%s"), gn);
151.  	} else if(mtmp->isshk) {
152.  		Sprintf(eos(buf), "%s %s, the shopkeeper",
153.  			(mtmp->female ? "Ms." : "Mr."), shkname(mtmp));
154.  		killer_format = KILLED_BY;
155.  	} else if (mtmp->ispriest || mtmp->isminion) {
156.  		killer = priestname(mtmp);
157.  		if (!strncmp(killer, "the ", 4)) Strcat(buf, killer+4);
158.  		else Strcat(buf, killer);
159.  	} else Strcat(buf, mtmp->data->mname);
160.  	if (mtmp->mnamelth) Sprintf(eos(buf), " called %s", NAME(mtmp));
161.  	killer = buf;
162.  	if (mtmp->data->mlet == S_WRAITH)
163.  		u.ugrave_arise = PM_WRAITH;
164.  	else if (mtmp->data->mlet == S_MUMMY)
165.  		u.ugrave_arise = (pl_character[0]=='E') ?
166.  						PM_ELF_MUMMY : PM_HUMAN_MUMMY;
167.  	else if (mtmp->data->mlet == S_VAMPIRE)
168.  		u.ugrave_arise = PM_VAMPIRE;
169.  	if (u.ugrave_arise > -1 && (mons[u.ugrave_arise].geno & G_GENOD))
170.  		u.ugrave_arise = -1;
171.  	if (mtmp->data->mlet == S_COCKATRICE)
172.  		done(STONING);
173.  	else
174.  		done(DIED);
175.  	return;
176.  }
177.  
178.  /*VARARGS1*/
179.  boolean panicking;
180.  extern boolean hu;	/* from save.c */
181.  
182.  void
183.  panic VA_DECL(const char *, str)
184.  	VA_START(str);
185.  	VA_INIT(str, char *);
186.  
187.  	if(panicking++)
188.  #ifdef AMIGA
189.  	    Abort(0);
190.  #else
191.  # ifdef SYSV
192.  	    (void)
193.  # endif
194.  		abort();    /* avoid loops - this should never happen*/
195.  #endif
196.  
197.  	if (flags.window_inited) exit_nhwindows(NULL);
198.  	flags.window_inited = 0; /* they're gone; force raw_print()ing */
199.  
200.  	raw_print(" Suddenly, the dungeon collapses.");
201.  #if defined(WIZARD) && !defined(MICRO)
202.  	if(!wizard) {
203.  	    raw_printf("Report error to %s and it may be possible to rebuild.",
204.  # ifdef WIZARD_NAME	/*(KR1ED)*/
205.  		WIZARD_NAME);
206.  # else
207.  		WIZARD);
208.  # endif
209.  	}
210.  	set_error_savefile();
211.  	hu = FALSE;
212.  	(void) dosave0();
213.  #endif
214.  	{
215.  	    char buf[BUFSZ];
216.  	    Vsprintf(buf,str,VA_ARGS);
217.  	    raw_print(buf);
218.  	}
219.  #if defined(WIZARD) && (defined(UNIX) || defined(VMS) || defined(LATTICE))
220.  	if (wizard)
221.  # ifdef AMIGA
222.  		Abort(0);
223.  # else
224.  #  ifdef SYSV
225.  		(void)
226.  #  endif
227.  		    abort();	/* generate core dump */
228.  # endif
229.  #endif
230.  	VA_END();
231.  	done(PANICKED);
232.  }
233.  
234.  static void
235.  disclose(how,taken)
236.  int how;
237.  boolean taken;
238.  {
239.  	char	c;
240.  	char	qbuf[QBUFSZ];
241.  
242.  	if(invent) {
243.  	    if(taken)
244.  		Sprintf(qbuf,"Do you want to see what you had when you %s?",
245.  			(how == QUIT) ? "quit" : "died");
246.  	    else
247.  		Strcpy(qbuf,"Do you want your possessions identified?");
248.  	    if ((c = yn_function(qbuf, ynqchars, 'y')) == 'y') {
249.  	    /* New dump format by maartenj@cs.vu.nl */
250.  		struct obj *obj;
251.  
252.  		for(obj = invent; obj && !done_stopprint; obj = obj->nobj) {
253.  		    makeknown(obj->otyp);
254.  		    obj->known = obj->bknown = obj->dknown = obj->rknown = 1;
255.  		}
256.  		(void) display_inventory(NULL, FALSE);
257.  		container_contents(invent, TRUE, TRUE);
258.  	    }
259.  	    if (c == 'q')  done_stopprint++;
260.  	    if (taken) {
261.  		/* paybill has already given the inventory locations
262.  		 * in the shop and put it on the main object list
263.  		 */
264.  		struct obj *obj;
265.  
266.  		for(obj = invent; obj; obj = obj->nobj) {
267.  		    obj->owornmask = 0;
268.  		    if(rn2(5)) curse(obj);
269.  		}
270.  		invent = (struct obj *) 0;
271.  	    }
272.  	}
273.  
274.  	if (!done_stopprint) {
275.  	    c = yn_function("Do you want to see your intrinsics?",ynqchars,'y');
276.  	    if (c == 'y') enlightenment(TRUE);	/* final */
277.  	    if (c == 'q') done_stopprint++;
278.  	}
279.  
280.  }
281.  
282.  /* try to get the player back in a viable state after being killed */
283.  static void
284.  savelife(how)
285.  int how;
286.  {
287.  	u.uswldtim = 0;
288.  	u.uhp = u.uhpmax;
289.  	if (u.uhunger < 500) {
290.  	    u.uhunger = 500;
291.  	    newuhs(FALSE);
292.  	}
293.  	if (how == CHOKING) init_uhunger();
294.  	nomovemsg = "You survived that attempt on your life.";
295.  	flags.move = 0;
296.  	if(multi > 0) multi = 0; else multi = -1;
297.  	if(u.utrap && u.utraptype == TT_LAVA) u.utrap = 0;
298.  	flags.botl = 1;
299.  	u.ugrave_arise = -1;
300.  	curs_on_u();
301.  }
302.  
303.  /*
304.   *  Get valuables from the given list. NOTE: The list is destroyed as it is
305.   *  processed, so don't expect to use it again!
306.   */
307.  static struct obj *
308.  get_valuables(list)
309.      struct obj *list;
310.  {
311.      struct obj *obj, *next_obj, *c_vals, *temp;
312.      struct obj *valuables = (struct obj *)0;
313.  
314.      for (obj = list; obj; obj = next_obj) {
315.  	if (Is_container(obj) && obj->cobj) {
316.  	    c_vals = get_valuables(obj->cobj);
317.  
318.  	    if (c_vals) {
319.  		/* find the end of the list */
320.  		for (temp = c_vals; temp->nobj; temp = temp->nobj) ;
321.  
322.  		temp->nobj = valuables;
323.  		valuables = c_vals;
324.  	    }
325.  	}
326.  
327.  	next_obj = obj->nobj;
328.  
329.  	if ((obj->oclass == GEM_CLASS && obj->otyp < LUCKSTONE)
330.  	    || obj->oclass == AMULET_CLASS) {
331.  	    obj->nobj = valuables;
332.  	    valuables = obj;
333.  	}
334.      }
335.      return valuables;
336.  }
337.  
338.  /* Be careful not to call panic from here! */
339.  void
340.  done(how)
341.  int how;
342.  {
343.  	struct permonst *upmon;
344.  	boolean taken;
345.  	char kilbuf[BUFSZ], pbuf[BUFSZ];
346.  	winid endwin = WIN_ERR;
347.  	boolean have_windows = flags.window_inited;
348.  
349.  	/* kilbuf: used to copy killer in case it comes from something like
350.  	 *	xname(), which would otherwise get overwritten when we call
351.  	 *	xname() when listing possessions
352.  	 * pbuf: holds Sprintf'd output for raw_print and putstr
353.  	 */
354.  	if (how == ASCENDED)
355.  		killer_format = NO_KILLER_PREFIX;
356.  	/* Avoid killed by "a" burning or "a" starvation */
357.  	if (!killer && (how == STARVING || how == BURNING))
358.  		killer_format = KILLED_BY;
359.  	Strcpy(kilbuf, (!killer || how >= PANICKED ? deaths[how] : killer));
360.  	killer = kilbuf;
361.  #ifdef WIZARD
362.  	if (wizard && how == TRICKED) {
363.  		You("are a very tricky wizard, it seems.");
364.  		return;
365.  	}
366.  #endif
367.  	if (Lifesaved && how <= GENOCIDED) {
368.  		pline("But wait...");
369.  		makeknown(AMULET_OF_LIFE_SAVING);
370.  		Your("medallion %s!",
371.  		      !Blind ? "begins to glow" : "feels warm");
372.  		if (how == CHOKING) You("vomit ...");
373.  		You("feel much better!");
374.  		pline("The medallion crumbles to dust!");
375.  		useup(uamul);
376.  
377.  		(void) adjattrib(A_CON, -1, TRUE);
378.  		if(u.uhpmax <= 0) u.uhpmax = 10;	/* arbitrary */
379.  		savelife(how);
380.  		if (how == GENOCIDED)
381.  			pline("Unfortunately you are still genocided...");
382.  		else {
383.  			killer = 0;
384.  			return;
385.  		}
386.  	}
387.  #if defined(WIZARD) || defined(EXPLORE_MODE)
388.  	if ((wizard || discover) && how <= GENOCIDED) {
389.  		if(yn("Die?") == 'y') goto die;
390.  		pline("OK, so you don't %s.",
391.  			(how == CHOKING) ? "choke" : "die");
392.  		if(u.uhpmax <= 0) u.uhpmax = u.ulevel * 8;	/* arbitrary */
393.  		savelife(how);
394.  		killer = 0;
395.  		return;
396.  	}
397.  #endif /* WIZARD || EXPLORE_MODE */
398.  	/* Sometimes you die on the first move.  Life's not fair.
399.  	 * On those rare occasions you get hosed immediately, go out
400.  	 * smiling... :-)  -3.
401.  	 */
402.  	if (moves <= 1 && how < QUIT)
403.  	    /* You die... --More-- */
404.  	    pline("Do not pass go.  Do not collect 200 zorkmids.");
405.  
406.  die:
407.  	if (have_windows) wait_synch();	/* flush screen output */
408.  #ifndef NO_SIGNAL
409.  	(void) signal(SIGINT, (SIG_RET_TYPE) done_intr);
410.  # if defined(UNIX) || defined(VMS)
411.  	(void) signal(SIGQUIT, (SIG_RET_TYPE) done_intr);
412.  	(void) signal(SIGHUP, (SIG_RET_TYPE) done_hangup);
413.  # endif
414.  #endif /* NO_SIGNAL /* */
415.  #ifdef POLYSELF
416.  	if (u.mtimedone)
417.  	    upmon = uasmon;
418.  	else
419.  #endif
420.  	upmon = player_mon();
421.  
422.  	if (u.ugrave_arise < 0) { /* >= 0 means create no corpse */
423.  	    if (how == STONING)
424.  		u.ugrave_arise = -2;
425.  
426.  /*
427.   * If you're burned to a crisp, why leave a corpse?
428.   */
429.  	    else if (how != BURNING && how != PANICKED)
430.  		(void) mk_named_object(CORPSE, upmon, u.ux, u.uy, plname,
431.  							(int)strlen(plname));
432.  	}
433.  
434.  	if (how == QUIT) {
435.  		killer_format = NO_KILLER_PREFIX;
436.  		if (u.uhp < 1) {
437.  			how = DIED;
438.  /* note that killer is pointing at kilbuf */
439.  			Strcpy(kilbuf, "quit while already on Charon's boat");
440.  		}
441.  	}
442.  	if (how == ESCAPED || how == PANICKED)
443.  		killer_format = NO_KILLER_PREFIX;
444.  
445.  	/* paybill() must be called unconditionally, or strange things will
446.  	 * happen to bones levels */
447.  	taken = paybill(how != QUIT);
448.  	paygd();
449.  	clearlocks();
450.  #ifdef AMIGA
451.  	clear_icon();
452.  #endif
453.  	if (have_windows) display_nhwindow(WIN_MESSAGE, FALSE);
454.  
455.  	if (flags.end_disclose && how != PANICKED) disclose(how,taken);
456.  
457.  	if (how < GENOCIDED) {
458.  #ifdef WIZARD
459.  	    if (!wizard || yn("Save bones?") == 'y')
460.  #endif
461.  		savebones();
462.  	}
463.  
464.  	/* clean up unneeded windows */
465.  	if (have_windows) {
466.  	    destroy_nhwindow(WIN_MAP);
467.  	    destroy_nhwindow(WIN_STATUS);
468.  	    destroy_nhwindow(WIN_MESSAGE);
469.  
470.  	    if(!done_stopprint || flags.tombstone)
471.  		endwin = create_nhwindow(NHW_TEXT);
472.  
473.  	    if(how < GENOCIDED && flags.tombstone) outrip(how, endwin);
474.  	} else
475.  	    done_stopprint = 1; /* just avoid any more output */
476.  
477.  /* changing kilbuf really changes killer. we do it this way because
478.     killer is declared a (const char *)
479.  */
480.  	if (u.uhave.amulet) Strcat(kilbuf, " (with the Amulet)");
481.  	if (!done_stopprint) {
482.  	    Sprintf(pbuf, "%s %s the %s...",
483.  		   (pl_character[0]=='S') ? "Sayonara" : "Goodbye", plname,
484.  		   how != ASCENDED ? (const char *) pl_character :
485.  		   (const char *) (flags.female ? "Demigoddess" : "Demigod"));
486.  	    putstr(endwin, 0, pbuf);
487.  	    putstr(endwin, 0, "");
488.  	}
489.  	{   long tmp;
490.  	    int deepest = deepest_lev_reached(FALSE);
491.  
492.  	    u.ugold += hidden_gold();	/* accumulate gold from containers */
493.  	    tmp = u.ugold - u.ugold0;
494.  	    if (tmp < 0L)
495.  		tmp = 0L;
496.  	    if (how < PANICKED)
497.  		tmp -= tmp / 10L;
498.  	    u.urexp += tmp;
499.  	    u.urexp += 50L * (long)(deepest - 1);
500.  	    if (deepest > 20)
501.  		u.urexp += 1000L * (long)((deepest > 30) ? 10 : deepest - 20);
502.  	    if (how == ASCENDED) u.urexp *= 2L;
503.  	}
504.  	if (how == ESCAPED || how == ASCENDED) {
505.  		register struct monst *mtmp;
506.  		register struct obj *otmp;
507.  		struct obj *jewels;
508.  		long i;
509.  		register long worthlessct = 0;
510.  
511.  		/*
512.  		 *  Put items that count into the jewels chain.  Rewriting
513.  		 *  the invent chain and all the container chains (within
514.  		 *  invent) here is safe.  They will never be used again.
515.  		 */
516.  		jewels = get_valuables(invent);
517.  
518.  		/* add points for jewels */
519.  		for(otmp = jewels; otmp; otmp = otmp->nobj) {
520.  			if(otmp->oclass == GEM_CLASS)
521.  				u.urexp += otmp->quan *
522.  					    objects[otmp->otyp].oc_cost;
523.  			else	/* amulet */
524.  				u.urexp += objects[otmp->otyp].oc_cost;
525.  		}
526.  
527.  		keepdogs();
528.  		viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */
529.  		mtmp = mydogs;
530.  		if(!done_stopprint) Strcpy(pbuf, "You");
531.  		if(mtmp) {
532.  			while(mtmp) {
533.  				if(!done_stopprint) {
534.  				    Strcat(pbuf, " and ");
535.  				    Strcat(pbuf, mon_nam(mtmp));
536.  				}
537.  				if(mtmp->mtame)
538.  					u.urexp += mtmp->mhp;
539.  				mtmp = mtmp->nmon;
540.  			}
541.  			if(!done_stopprint)
542.  				putstr(endwin, 0, pbuf);
543.  			pbuf[0] = 0;
544.  		} else {
545.  			if(!done_stopprint)
546.  				Strcat(pbuf, " ");
547.  		}
548.  		if(!done_stopprint) {
549.  			Sprintf(eos(pbuf),
550.  				"%s with %ld point%s,",
551.  				how==ASCENDED ? "went to your reward"
552.  				: "escaped from the dungeon",
553.  				u.urexp, plur(u.urexp));
554.  			putstr(endwin, 0, pbuf);
555.  		}
556.  
557.  		/* print jewels chain here */
558.  		for(otmp = jewels; otmp; otmp = otmp->nobj) {
559.  			makeknown(otmp->otyp);
560.  			if(otmp->oclass == GEM_CLASS &&
561.  			   otmp->otyp < LUCKSTONE) {
562.  				i = otmp->quan *
563.  					objects[otmp->otyp].oc_cost;
564.  				if(i == 0) {
565.  					worthlessct += otmp->quan;
566.  					continue;
567.  				}
568.  			} else {		/* amulet */
569.  				otmp->known = 1;
570.  				i = objects[otmp->otyp].oc_cost;
571.  			}
572.  			if(!done_stopprint) {
573.  			    Sprintf(pbuf, "        %s (worth %ld zorkmids),",
574.  				    doname(otmp), i);
575.  			    putstr(endwin, 0, pbuf);
576.  			}
577.  		}
578.  		if(worthlessct && !done_stopprint) {
579.  		    Sprintf(pbuf,
580.  			  "        %ld worthless piece%s of colored glass,",
581.  			  worthlessct, plur(worthlessct));
582.  		    putstr(endwin, 0, pbuf);
583.  		}
584.  	} else if (!done_stopprint) {
585.  		Strcpy(pbuf, "You ");
586.  		Strcat(pbuf, ends[how]);
587.  		if (how != ASCENDED) {
588.  		    Strcat(pbuf, " in ");
589.  		    if (Is_astralevel(&u.uz))
590.  			Strcat(pbuf, "The Astral Plane");
591.  		    else Strcat(pbuf, dungeons[u.uz.dnum].dname);
592.  		    Strcat(pbuf, " ");
593.  		    if (!In_endgame(&u.uz)
594.  #ifdef MULDGN
595.  					       && !Is_knox(&u.uz)
596.  #endif
597.  			)
598.  			Sprintf(eos(pbuf), "on dungeon level %d ", (
599.  #ifdef MULDGN
600.  						 In_quest(&u.uz) ?
601.  						    dunlev(&u.uz) :
602.  #endif
603.  						    depth(&u.uz)));
604.  		}
605.  		Sprintf(eos(pbuf),
606.  			"with %ld point%s,", u.urexp, plur(u.urexp));
607.  		putstr(endwin, 0, pbuf);
608.  	}
609.  	if (!done_stopprint) {
610.  	    Sprintf(pbuf, "and %ld piece%s of gold, after %ld move%s.",
611.  		    u.ugold, plur(u.ugold), moves, plur(moves));
612.  	    putstr(endwin, 0, pbuf);
613.  	}
614.  	if (!done_stopprint) {
615.  	    Sprintf(pbuf,
616.  	     "You were level %u with a maximum of %d hit point%s when you %s.",
617.  		    u.ulevel, u.uhpmax, plur(u.uhpmax), ends[how]);
618.  	    putstr(endwin, 0, pbuf);
619.  	    putstr(endwin, 0, "");
620.  	}
621.  #if (defined(WIZARD) || defined(EXPLORE_MODE))
622.  # ifndef LOGFILE
623.  	if (wizard || discover) {
624.  	    if (!done_stopprint) {
625.  		putstr(endwin, 0, "");
626.  		Sprintf(pbuf, "Since you were in %s mode, the score list \
627.  will not be checked.", wizard ? "wizard" : "discover");
628.  		putstr(endwin, 0, pbuf);
629.  		putstr(endwin, 0, "");
630.  		display_nhwindow(endwin, TRUE);
631.  	    }
632.  	    if (have_windows)
633.  		exit_nhwindows(NULL);
634.  	} else
635.  # endif
636.  #endif
637.  	{
638.  	    if (!done_stopprint)
639.  		display_nhwindow(endwin, TRUE);
640.  	    if (have_windows)
641.  		exit_nhwindows(NULL);
642.  /* "So when I die, the first thing I will see in Heaven is a score list?" */
643.  	    topten(how);
644.  	}
645.  	if(done_stopprint) { raw_print(""); raw_print(""); }
646.  	terminate(0);
647.  }
648.  
649.  
650.  #ifdef NOSAVEONHANGUP
651.  int
652.  hangup()
653.  {
654.  	(void) signal(SIGINT, SIG_IGN);
655.  	clearlocks();
656.  # ifndef VMS
657.  	terminate(1);
658.  # endif
659.  }
660.  #endif
661.  
662.  
663.  void
664.  container_contents(list, identified, all_containers)
665.  	struct obj *list;
666.  	boolean identified, all_containers;
667.  {
668.  	register struct obj *box, *obj;
669.  	char buf[BUFSZ];
670.  
671.  	for (box = list; box; box = box->nobj) {
672.  	    if (Is_container(box) && box->otyp != BAG_OF_TRICKS) {
673.  		if (box->cobj) {
674.  		    winid tmpwin = create_nhwindow(NHW_MENU);
675.  		    Sprintf(buf, "Contents of the %s:", xname(box));
676.  		    putstr(tmpwin, 0, buf); putstr(tmpwin, 0, "");
677.  		    for (obj = box->cobj; obj; obj = obj->nobj) {
678.  			if (identified) {
679.  			    makeknown(obj->otyp);
680.  			    obj->known = obj->bknown = obj->dknown = 1;
681.  			}
682.  			putstr(tmpwin, 0, doname(obj));
683.  		    }
684.  		    display_nhwindow(tmpwin, TRUE);
685.  		    destroy_nhwindow(tmpwin);
686.  		    if (all_containers)
687.  			container_contents(box->cobj, identified, TRUE);
688.  		} else {
689.  		    pline("%s is empty.", The(xname(box)));
690.  		    display_nhwindow(WIN_MESSAGE, FALSE);
691.  		}
692.  	    }
693.  	    if (!all_containers)
694.  		break;
695.  	}
696.  }
697.  
698.  void
699.  terminate(status)
700.  int status;
701.  {
702.  #ifdef MAC
703.  	if (!hu) {
704.  		int idx;
705.  		for (idx = theWindows[BASE_WINDOW].windowTextLen; --idx >= 0; )
706.  			/* If there is something to show... */
707.  			if (((unsigned char *)*theWindows[BASE_WINDOW].windowText)[idx] > ' ') {
708.  				display_nhwindow(BASE_WINDOW, TRUE);
709.  				break;
710.  			}
711.  	}
712.  #endif
713.  	exit(status);
714.  }
715.  
716.  /*end.c*/