Source:NetHack 3.2.0/end.c

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

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   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_printing */ 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*/