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