Source:NetHack 3.3.0/end.c

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

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