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. */
5
#define NEED_VARARGS /* comment line for pre-compiled headers */
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
19
struct valuable_data { long count; int typ; };
21
static struct valuable_data
22
gems[LAST_GEM+1 - FIRST_GEM + 1], /* 1 extra for glass */
23
amulets[LAST_AMULET+1 - FIRST_AMULET];
25
static struct val_list { struct valuable_data *list; int size; } valuables[] = {
26
{ gems, sizeof gems / sizeof *gems },
27
{ amulets, sizeof amulets / sizeof *amulets },
32
STATIC_PTR void FDECL(done_intr, (int));
33
# if defined(UNIX) || defined(VMS) || defined (__EMX__)
34
static void FDECL(done_hangup, (int));
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));
44
extern void NDECL(dump_spells);
45
void FDECL(do_vanquished, (int, BOOLEAN_P, BOOLEAN_P));
46
STATIC_DCL void FDECL(list_genocided, (int, BOOLEAN_P, BOOLEAN_P));
48
STATIC_DCL void FDECL(list_genocided, (CHAR_P,BOOLEAN_P));
50
STATIC_DCL boolean FDECL(should_query_disclose_option, (int,char *));
52
#if defined(__BEOS__) || defined(MICRO) || defined(WIN32) || defined(OS2)
53
extern void FDECL(nethack_exit,(int));
55
#define nethack_exit exit
58
#define done_stopprint program_state.stopprint
61
# define NH_abort() Abort(0)
64
# define NH_abort() (void) abort()
67
# define NH_abort() win32_abort()
69
# define NH_abort() abort()
75
* The order of these needs to match the macros in hack.h.
77
static NEARDATA const char *deaths[] = { /* the array of death */
78
"died", "choked", "poisoned", "starvation", "drowning",
79
"burning", "dissolving under the heat and pressure",
80
"crushed", "turned to stone", "turned into slime",
81
"genocided", "panic", "trickery",
82
"quit", "escaped", "ascended"
85
static NEARDATA const char *ends[] = { /* "when you..." */
86
"died", "choked", "were poisoned", "starved", "drowned",
87
"burned", "dissolved in the lava",
88
"were crushed", "turned to stone", "turned into slime",
89
"were genocided", "panicked", "were tricked",
90
"quit", "escaped", "ascended"
93
extern const char * const killed_by_prefix[]; /* from topten.c */
96
FILE *dump_fp = (FILE *)0; /* file pointer for dumps */
97
/* functions dump_init, dump_exit and dump are from the dump patch */
103
char *p = (char *) strstr(dump_fn, "%n");
105
int new_dump_fn_len = strlen(dump_fn)+strlen(plname)-2; /* %n */
106
char *new_dump_fn = (char *) alloc((unsigned)(new_dump_fn_len+1));
107
char *q = new_dump_fn;
108
strncpy(q, dump_fn, p-dump_fn);
110
strncpy(q, plname, strlen(plname) + 1);
112
q[strlen(plname)] = '\0';
114
p += 2; /* skip "%n" */
115
strncpy(q, p, strlen(p));
116
new_dump_fn[new_dump_fn_len] = '\0';
118
dump_fp = fopen(new_dump_fn, "w");
120
pline("Can't open %s for output.", new_dump_fn);
121
pline("Dump file not created.");
126
dump_fp = fopen (dump_fn, "w");
129
pline("Can't open %s for output.", dump_fn);
130
pline("Dump file not created.");
147
fprintf (dump_fp, "%s%s\n", pre, str);
149
#endif /* DUMP_LOG */
153
done1(sig_unused) /* called as signal() handler, so sent at least one arg */
157
(void) signal(SIGINT,SIG_IGN);
161
(void) signal(SIGINT, (SIG_RET_TYPE) done1);
163
clear_nhwindow(WIN_MESSAGE);
166
if(multi > 0) nomul(0);
173
/* "#quit" command or keyboard interrupt */
177
if(yn("Really quit?") == 'n') {
179
(void) signal(SIGINT, (SIG_RET_TYPE) done1);
181
clear_nhwindow(WIN_MESSAGE);
184
if(multi > 0) nomul(0);
186
u.uinvulnerable = FALSE; /* avoid ctrl-C bug -dlc */
191
#if defined(WIZARD) && (defined(UNIX) || defined(VMS) || defined(LATTICE))
195
const char *tmp = "Enter debugger?";
198
const char *tmp = "Create SnapShot?";
200
const char *tmp = "Dump core?";
203
if ((c = ynq(tmp)) == 'y') {
204
(void) signal(SIGINT, (SIG_RET_TYPE) done1);
205
exit_nhwindows((char *)0);
207
} else if (c == 'q') done_stopprint++;
219
done_intr(sig_unused) /* called as signal() handler, so sent at least one arg */
223
(void) signal(SIGINT, SIG_IGN);
224
# if defined(UNIX) || defined(VMS)
225
(void) signal(SIGQUIT, SIG_IGN);
230
# if defined(UNIX) || defined(VMS) || defined(__EMX__)
232
done_hangup(sig) /* signal() handler */
235
program_state.done_hup++;
236
(void)signal(SIGHUP, SIG_IGN);
241
#endif /* NO_SIGNAL */
245
register struct monst *mtmp;
248
boolean distorted = (boolean)(Hallucination && canspotmon(mtmp));
251
mark_synch(); /* flush buffered screen output */
253
killer_format = KILLED_BY_AN;
254
/* "killed by the high priest of Crom" is okay, "killed by the high
255
priest" alone isn't */
256
if ((mtmp->data->geno & G_UNIQ) != 0 && !(mtmp->data == &mons[PM_HIGH_PRIEST] && !mtmp->ispriest)) {
257
if (!type_is_pname(mtmp->data))
259
killer_format = KILLED_BY;
261
/* _the_ <invisible> <distorted> ghost of Dudley */
262
if (mtmp->data == &mons[PM_GHOST] && mtmp->mnamelth) {
264
killer_format = KILLED_BY;
267
Strcat(buf, "invisible ");
269
Strcat(buf, "hallucinogen-distorted ");
271
if(mtmp->data == &mons[PM_GHOST]) {
272
Strcat(buf, "ghost");
273
if (mtmp->mnamelth) Sprintf(eos(buf), " of %s", NAME(mtmp));
274
} else if(mtmp->isshk) {
275
Sprintf(eos(buf), "%s %s, the shopkeeper",
276
(mtmp->female ? "Ms." : "Mr."), shkname(mtmp));
277
killer_format = KILLED_BY;
278
} else if (mtmp->ispriest || mtmp->isminion) {
279
/* m_monnam() suppresses "the" prefix plus "invisible", and
280
it overrides the effect of Hallucination on priestname() */
281
killer = m_monnam(mtmp);
284
Strcat(buf, mtmp->data->mname);
286
Sprintf(eos(buf), " called %s", NAME(mtmp));
289
if (multi) Strcat(buf, ", while helpless");
291
if (mtmp->data->mlet == S_WRAITH)
292
u.ugrave_arise = PM_WRAITH;
293
else if (mtmp->data->mlet == S_MUMMY && urace.mummynum != NON_PM)
294
u.ugrave_arise = urace.mummynum;
295
else if (mtmp->data->mlet == S_VAMPIRE && Race_if(PM_HUMAN))
296
u.ugrave_arise = PM_VAMPIRE;
297
else if (mtmp->data == &mons[PM_GHOUL])
298
u.ugrave_arise = PM_GHOUL;
299
if (u.ugrave_arise >= LOW_PM &&
300
(mvitals[u.ugrave_arise].mvflags & G_GENOD))
301
u.ugrave_arise = NON_PM;
302
if (touch_petrifies(mtmp->data))
310
#define NOTIFY_NETHACK_BUGS
315
panic VA_DECL(const char *, str)
317
VA_INIT(str, char *);
319
if (program_state.panicking++)
320
NH_abort(); /* avoid loops - this should never happen*/
322
if (iflags.window_inited) {
323
raw_print("\r\nOops...");
324
wait_synch(); /* make sure all pending output gets flushed */
325
exit_nhwindows((char *)0);
326
iflags.window_inited = 0; /* they're gone; force raw_print()ing */
329
raw_print(program_state.gameover ?
330
"Postgame wrapup disrupted." :
331
!program_state.something_worth_saving ?
332
"Program initialization has failed." :
333
"Suddenly, the dungeon collapses.");
334
#if defined(WIZARD) && !defined(MICRO)
335
# if defined(NOTIFY_NETHACK_BUGS)
337
raw_printf("Report the following error to \"%s\".",
338
"nethack-bugs@nethack.org");
339
else if (program_state.something_worth_saving)
340
raw_print("\nError save file being written.\n");
343
raw_printf("Report error to \"%s\"%s.",
344
# ifdef WIZARD_NAME /*(KR1ED)*/
349
!program_state.something_worth_saving ? "" :
350
" and it may be possible to rebuild.");
352
if (program_state.something_worth_saving) {
353
set_error_savefile();
359
Vsprintf(buf,str,VA_ARGS);
361
paniclog("panic", buf);
364
interject(INTERJECT_PANIC);
366
#if defined(WIZARD) && (defined(UNIX) || defined(VMS) || defined(LATTICE) || defined(WIN32))
368
NH_abort(); /* generate core dump */
375
should_query_disclose_option(category, defquery)
380
char *dop = index(disclosure_options, category);
382
if (dop && defquery) {
383
idx = dop - disclosure_options;
384
if (idx < 0 || idx > (NUM_DISCLOSURE_OPTIONS - 1)) {
386
"should_query_disclose_option: bad disclosure index %d %c",
388
*defquery = DISCLOSE_PROMPT_DEFAULT_YES;
391
if (flags.end_disclose[idx] == DISCLOSE_YES_WITHOUT_PROMPT) {
394
} else if (flags.end_disclose[idx] == DISCLOSE_NO_WITHOUT_PROMPT) {
397
} else if (flags.end_disclose[idx] == DISCLOSE_PROMPT_DEFAULT_YES) {
400
} else if (flags.end_disclose[idx] == DISCLOSE_PROMPT_DEFAULT_NO) {
406
impossible("should_query_disclose_option: bad category %c", category);
408
impossible("should_query_disclose_option: null defquery");
417
char c = 0, defquery;
423
Sprintf(qbuf,"Do you want to see what you had when you %s?",
424
(how == QUIT) ? "quit" : "died");
426
Strcpy(qbuf,"Do you want your possessions identified?");
428
ask = should_query_disclose_option('i', &defquery);
429
if (!done_stopprint) {
430
c = ask ? yn_function(qbuf, ynqchars, defquery) : defquery;
434
for (obj = invent; obj; obj = obj->nobj) {
435
makeknown(obj->otyp);
436
obj->known = obj->bknown = obj->dknown = obj->rknown = 1;
439
(void) dump_inventory((char *)0, TRUE);
440
do_containerconts(invent, TRUE, TRUE, TRUE);
442
(void) display_inventory((char *)0, TRUE);
443
container_contents(invent, TRUE, TRUE);
444
#endif /* DUMP_LOG */
446
if (c == 'q') done_stopprint++;
450
ask = should_query_disclose_option('a', &defquery);
451
if (!done_stopprint) {
452
c = ask ? yn_function("Do you want to see your attributes?",
453
ynqchars, defquery) : defquery;
455
enlightenment(how >= PANICKED ? 1 : 2); /* final */
456
if (c == 'q') done_stopprint++;
460
dump_enlightenment((int) (how >= PANICKED ? 1 : 2));
465
ask = should_query_disclose_option('v', &defquery);
468
do_vanquished(defquery, ask, TRUE);
470
list_vanquished(defquery, ask);
473
ask = should_query_disclose_option('g', &defquery);
476
list_genocided(defquery, ask,TRUE);
478
list_genocided(defquery, ask);
481
ask = should_query_disclose_option('c', &defquery);
482
if (!done_stopprint) {
483
c = ask ? yn_function("Do you want to see your conduct?",
484
ynqchars, defquery) : defquery;
486
show_conduct(how >= PANICKED ? 1 : 2);
487
if (c == 'q') done_stopprint++;
491
dump_conduct(how >= PANICKED ? 1 : 2);
497
/* try to get the player back in a viable state after being killed */
504
if (u.uhunger < 500) {
508
/* cure impending doom of sickness hero won't have time to fix */
509
if ((Sick & TIMEOUT) == 1) {
513
if (how == CHOKING) init_uhunger();
514
nomovemsg = "You survived that attempt on your life.";
516
if(multi > 0) multi = 0; else multi = -1;
517
if(u.utrap && u.utraptype == TT_LAVA) u.utrap = 0;
519
u.ugrave_arise = NON_PM;
525
* Get valuables from the given list. Revised code: the list always remains
530
struct obj *list; /* inventory or container contents */
532
register struct obj *obj;
535
/* find amulets and gems, ignoring all artifacts */
536
for (obj = list; obj; obj = obj->nobj)
537
if (Has_contents(obj)) {
538
get_valuables(obj->cobj);
539
} else if (obj->oartifact) {
541
} else if (obj->oclass == AMULET_CLASS) {
542
i = obj->otyp - FIRST_AMULET;
543
if (!amulets[i].count) {
544
amulets[i].count = obj->quan;
545
amulets[i].typ = obj->otyp;
546
} else amulets[i].count += obj->quan; /* always adds one */
547
} else if (obj->oclass == GEM_CLASS && obj->otyp < LUCKSTONE) {
548
i = min(obj->otyp, LAST_GEM + 1) - FIRST_GEM;
549
if (!gems[i].count) {
550
gems[i].count = obj->quan;
551
gems[i].typ = obj->otyp;
552
} else gems[i].count += obj->quan;
558
* Sort collected valuables, most frequent to least. We could just
559
* as easily use qsort, but we don't care about efficiency here.
562
sort_valuables(list, size)
563
struct valuable_data list[];
564
int size; /* max value is less than 20 */
567
struct valuable_data ltmp;
569
/* move greater quantities to the front of the list */
570
for (i = 1; i < size; i++) {
571
if (list[i].count == 0) continue; /* empty slot */
572
ltmp = list[i]; /* structure copy */
573
for (j = i; j > 0; --j)
574
if (list[j-1].count >= ltmp.count) break;
583
/* called twice; first to calculate total, then to list relevant items */
585
artifact_score(list, counting, endwin)
587
boolean counting; /* true => add up points; false => display them */
593
short dummy; /* object type returned by artifact_name() */
595
for (otmp = list; otmp; otmp = otmp->nobj) {
596
if (otmp->oartifact ||
597
otmp->otyp == BELL_OF_OPENING ||
598
otmp->otyp == SPE_BOOK_OF_THE_DEAD ||
599
otmp->otyp == CANDELABRUM_OF_INVOCATION) {
600
value = arti_cost(otmp); /* zorkmid value */
601
points = value * 5 / 2; /* score value */
605
makeknown(otmp->otyp);
606
otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
607
/* assumes artifacts don't have quan > 1 */
608
Sprintf(pbuf, "%s%s (worth %ld %s and %ld points)",
609
the_unique_obj(otmp) ? "The " : "",
610
otmp->oartifact ? artifact_name(xname(otmp), &dummy) :
611
OBJ_NAME(objects[otmp->otyp]),
612
value, currency(value), points);
613
putstr(endwin, 0, pbuf);
620
if (Has_contents(otmp))
621
artifact_score(otmp->cobj, counting, endwin);
625
/* Be careful not to call panic from here! */
631
char kilbuf[BUFSZ], pbuf[BUFSZ];
632
winid endwin = WIN_ERR;
633
boolean bones_ok, have_windows = iflags.window_inited;
634
struct obj *corpse = (struct obj *)0;
637
if (how == TRICKED) {
639
paniclog("trickery", killer);
644
You("are a very tricky wizard, it seems.");
650
/* kilbuf: used to copy killer in case it comes from something like
651
* xname(), which would otherwise get overwritten when we call
652
* xname() when listing possessions
653
* pbuf: holds Sprintf'd output for raw_print and putstr
655
if (how == ASCENDED || (!killer && how == GENOCIDED))
656
killer_format = NO_KILLER_PREFIX;
657
/* Avoid killed by "a" burning or "a" starvation */
658
if (!killer && (how == STARVING || how == BURNING))
659
killer_format = KILLED_BY;
660
Strcpy(kilbuf, (!killer || how >= PANICKED ? deaths[how] : killer));
663
if (how < PANICKED) u.umortality++;
664
if (Lifesaved && (how <= GENOCIDED)) {
665
pline("But wait...");
666
makeknown(AMULET_OF_LIFE_SAVING);
667
Your("medallion %s!",
668
!Blind ? "begins to glow" : "feels warm");
669
if (how == CHOKING) You("vomit ...");
670
You_feel("much better!");
671
pline_The("medallion crumbles to dust!");
672
if (uamul) useup(uamul);
674
(void) adjattrib(A_CON, -1, TRUE);
675
if(u.uhpmax <= 0) u.uhpmax = 10; /* arbitrary */
677
if (how == GENOCIDED)
678
pline("Unfortunately you are still genocided...");
689
discover) && (how <= GENOCIDED)) {
690
if(yn("Die?") == 'y') goto die;
691
pline("OK, so you don't %s.",
692
(how == CHOKING) ? "choke" : "die");
693
if(u.uhpmax <= 0) u.uhpmax = u.ulevel * 8; /* arbitrary */
701
* The game is now over...
705
program_state.gameover = 1;
706
/* in case of a subsequent panic(), there's no point trying to save */
707
program_state.something_worth_saving = 0;
709
/* D: Grab screen dump right here */
712
Sprintf(pbuf, "%s, %s %s %s %s", plname,
713
aligns[1 - u.ualign.type].adj,
714
genders[flags.female].adj,
716
(flags.female && urole.name.f)?
717
urole.name.f : urole.name.m);
719
/* D: Add a line for clearance from the screen dump */
723
#endif /* DUMP_LOG */
724
/* render vision subsystem inoperative */
725
iflags.vision_inited = 0;
726
/* might have been killed while using a disposable item, so make sure
727
it's gone prior to inventory disclosure and creation of bones data */
730
/* Sometimes you die on the first move. Life's not fair.
731
* On those rare occasions you get hosed immediately, go out
734
if (moves <= 1 && how < PANICKED) /* You die... --More-- */
735
pline("Do not pass go. Do not collect 200 %s.", currency(200L));
737
if (have_windows) wait_synch(); /* flush screen output */
739
(void) signal(SIGINT, (SIG_RET_TYPE) done_intr);
740
# if defined(UNIX) || defined(VMS) || defined (__EMX__)
741
(void) signal(SIGQUIT, (SIG_RET_TYPE) done_intr);
742
(void) signal(SIGHUP, (SIG_RET_TYPE) done_hangup);
744
#endif /* NO_SIGNAL */
746
bones_ok = (how < GENOCIDED) && can_make_bones();
748
if (how == TURNED_SLIME)
749
u.ugrave_arise = PM_GREEN_SLIME;
751
if (bones_ok && u.ugrave_arise < LOW_PM) {
752
/* corpse gets burnt up too */
754
u.ugrave_arise = (NON_PM - 2); /* leave no corpse */
755
else if (how == STONING)
756
u.ugrave_arise = (NON_PM - 1); /* statue instead of corpse */
757
else if (u.ugrave_arise == NON_PM &&
758
!(mvitals[u.umonnum].mvflags & G_NOCORPSE)) {
759
int mnum = u.umonnum;
762
/* Base corpse on race when not poly'd since original
763
* u.umonnum is based on role, and all role monsters
766
mnum = (flags.female && urace.femalenum != NON_PM) ?
767
urace.femalenum : urace.malenum;
769
corpse = mk_named_object(CORPSE, &mons[mnum],
771
Sprintf(pbuf, "%s, %s%s", plname,
772
killer_format == NO_KILLER_PREFIX ? "" :
773
killed_by_prefix[how],
774
killer_format == KILLED_BY_AN ? an(killer) : killer);
775
make_grave(u.ux, u.uy, pbuf);
780
killer_format = NO_KILLER_PREFIX;
783
u.umortality++; /* skipped above when how==QUIT */
784
/* note that killer is pointing at kilbuf */
785
Strcpy(kilbuf, "quit while already on Charon's boat");
788
if (how == ESCAPED || how == PANICKED)
789
killer_format = NO_KILLER_PREFIX;
791
if (how != PANICKED) {
792
/* these affect score and/or bones, but avoid them during panic */
793
taken = paybill((how == ESCAPED) ? -1 : (how != QUIT));
796
} else taken = FALSE; /* lint; assert( !bones_ok ); */
800
if (have_windows) display_nhwindow(WIN_MESSAGE, FALSE);
802
if (strcmp(flags.end_disclose, "none") && how != PANICKED)
803
disclose(how, taken);
804
/* finish_paybill should be called after disclosure but before bones */
805
if (bones_ok && taken) finish_paybill();
807
/* calculate score, before creating bones [container gold] */
810
int deepest = deepest_lev_reached(FALSE);
816
umoney = money_cnt(invent);
819
umoney += hidden_gold(); /* accumulate gold from containers */
820
tmp = umoney - tmp; /* net gain */
827
u.urexp += 50L * (long)(deepest - 1);
829
u.urexp += 1000L * (long)((deepest > 30) ? 10 : deepest - 20);
830
if (how == ASCENDED) u.urexp *= 2L;
835
if (!wizard || yn("Save bones?") == 'y')
838
/* corpse may be invalid pointer now so
839
ensure that it isn't used again */
840
corpse = (struct obj *)0;
843
/* update gold for the rip output, which can't use hidden_gold()
844
(containers will be gone by then if bones just got saved...) */
851
/* clean up unneeded windows */
854
display_nhwindow(WIN_MESSAGE, TRUE);
855
destroy_nhwindow(WIN_MAP);
856
destroy_nhwindow(WIN_STATUS);
857
destroy_nhwindow(WIN_MESSAGE);
858
WIN_MESSAGE = WIN_STATUS = WIN_MAP = WIN_ERR;
860
if(!done_stopprint || flags.tombstone)
861
endwin = create_nhwindow(NHW_TEXT);
863
if (how < GENOCIDED && flags.tombstone && endwin != WIN_ERR)
866
done_stopprint = 1; /* just avoid any more output */
868
/* changing kilbuf really changes killer. we do it this way because
869
killer is declared a (const char *)
871
if (u.uhave.amulet) Strcat(kilbuf, " (with the Amulet)");
872
else if (how == ESCAPED) {
873
if (Is_astralevel(&u.uz)) /* offered Amulet to wrong deity */
874
Strcat(kilbuf, " (in celestial disgrace)");
875
else if (carrying(FAKE_AMULET_OF_YENDOR))
876
Strcat(kilbuf, " (with a fake Amulet)");
877
/* don't bother counting to see whether it should be plural */
880
Sprintf(pbuf, "%s %s the %s...", Goodbye(), plname,
882
(const char *) ((flags.female && urole.name.f) ?
883
urole.name.f : urole.name.m) :
884
(const char *) (flags.female ? "Demigoddess" : "Demigod"));
885
if (!done_stopprint) {
886
putstr(endwin, 0, pbuf);
887
putstr(endwin, 0, "");
890
if (dump_fp) dump("", pbuf);
893
if (how == ESCAPED || how == ASCENDED) {
894
register struct monst *mtmp;
895
register struct obj *otmp;
896
register struct val_list *val;
899
for (val = valuables; val->list; val++)
900
for (i = 0; i < val->size; i++) {
901
val->list[i].count = 0L;
903
get_valuables(invent);
905
/* add points for collected valuables */
906
for (val = valuables; val->list; val++)
907
for (i = 0; i < val->size; i++)
908
if (val->list[i].count != 0L)
909
u.urexp += val->list[i].count
910
* (long)objects[val->list[i].typ].oc_cost;
912
/* count the points for artifacts */
913
artifact_score(invent, TRUE, endwin);
916
viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */
921
Sprintf(eos(pbuf), " and %s", mon_nam(mtmp));
923
u.urexp += mtmp->mhp;
926
if (!done_stopprint) putstr(endwin, 0, pbuf);
928
if (dump_fp) dump("", pbuf);
932
if (!done_stopprint) Strcat(pbuf, " ");
934
Sprintf(eos(pbuf), "%s with %ld point%s,",
935
how==ASCENDED ? "went to your reward" :
936
"escaped from the dungeon",
937
u.urexp, plur(u.urexp));
939
if (dump_fp) dump("", pbuf);
941
if (!done_stopprint) {
942
putstr(endwin, 0, pbuf);
946
artifact_score(invent, FALSE, endwin); /* list artifacts */
948
/* list valuables here */
949
for (val = valuables; val->list; val++) {
950
sort_valuables(val->list, val->size);
951
for (i = 0; i < val->size && !done_stopprint; i++) {
952
int typ = val->list[i].typ;
953
long count = val->list[i].count;
955
if (count == 0L) continue;
956
if (objects[typ].oc_class != GEM_CLASS || typ <= LAST_GEM) {
957
otmp = mksobj(typ, FALSE, FALSE);
958
makeknown(otmp->otyp);
959
otmp->known = 1; /* for fake amulets */
960
otmp->dknown = 1; /* seen it (blindness fix) */
963
Sprintf(pbuf, "%8ld %s (worth %ld %s),",
965
count * (long)objects[typ].oc_cost, currency(2L));
966
obfree(otmp, (struct obj *)0);
969
"%8ld worthless piece%s of colored glass,",
972
putstr(endwin, 0, pbuf);
974
if (dump_fp) dump("", pbuf);
979
} else if (!done_stopprint) {
980
/* did not escape or ascend */
981
if (u.uz.dnum == 0 && u.uz.dlevel <= 0) {
982
/* level teleported out of the dungeon; `how' is DIED,
983
due to falling or to "arriving at heaven prematurely" */
984
Sprintf(pbuf, "You %s beyond the confines of the dungeon",
985
(u.uz.dlevel < 0) ? "passed away" : ends[how]);
987
/* more conventional demise */
988
const char *where = dungeons[u.uz.dnum].dname;
990
if (Is_astralevel(&u.uz)) where = "The Astral Plane";
991
Sprintf(pbuf, "You %s in %s", ends[how], where);
992
if (!In_endgame(&u.uz) && !Is_knox(&u.uz))
993
Sprintf(eos(pbuf), " on dungeon level %d",
994
In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz));
997
Sprintf(eos(pbuf), " with %ld point%s,",
998
u.urexp, plur(u.urexp));
999
putstr(endwin, 0, pbuf);
1001
if (dump_fp) dump("", pbuf);
1005
if (!done_stopprint) {
1006
Sprintf(pbuf, "and %ld piece%s of gold, after %ld move%s.",
1007
umoney, plur(umoney), moves, plur(moves));
1008
putstr(endwin, 0, pbuf);
1012
Sprintf(pbuf, "Killer: %s", killer);
1017
if (!done_stopprint) {
1019
"You were level %d with a maximum of %d hit point%s when you %s.",
1020
u.ulevel, u.uhpmax, plur(u.uhpmax), ends[how]);
1021
putstr(endwin, 0, pbuf);
1022
putstr(endwin, 0, "");
1024
if (dump_fp) dump("", pbuf);
1027
if (!done_stopprint)
1028
display_nhwindow(endwin, TRUE);
1029
if (endwin != WIN_ERR)
1030
destroy_nhwindow(endwin);
1032
/* "So when I die, the first thing I will see in Heaven is a
1034
if (flags.toptenwin) {
1037
exit_nhwindows((char *)0);
1040
exit_nhwindows((char *)0);
1044
if (dump_fp) dump_exit();
1047
if(done_stopprint) { raw_print(""); raw_print(""); }
1048
terminate(EXIT_SUCCESS);
1053
container_contents(list, identified, all_containers)
1055
boolean identified, all_containers;
1058
do_containerconts(list, identified, all_containers, FALSE);
1061
void do_containerconts(list, identified, all_containers, want_dump)
1063
boolean identified, all_containers, want_dump;
1065
/* The original container_contents function */
1067
register struct obj *box, *obj;
1070
for (box = list; box; box = box->nobj) {
1071
if (Is_container(box) || box->otyp == STATUE) {
1072
if (box->otyp == BAG_OF_TRICKS) {
1073
continue; /* wrong type of container */
1074
} else if (box->cobj) {
1075
winid tmpwin = create_nhwindow(NHW_MENU);
1076
Sprintf(buf, "Contents of %s:", the(xname(box)));
1077
putstr(tmpwin, 0, buf);
1078
putstr(tmpwin, 0, "");
1080
if (dump_fp) dump("", buf);
1082
for (obj = box->cobj; obj; obj = obj->nobj) {
1084
makeknown(obj->otyp);
1085
obj->known = obj->bknown =
1086
obj->dknown = obj->rknown = 1;
1088
putstr(tmpwin, 0, doname(obj));
1090
if (want_dump) dump(" ", doname(obj));
1094
if (want_dump) dump("","");
1096
display_nhwindow(tmpwin, TRUE);
1097
destroy_nhwindow(tmpwin);
1098
if (all_containers) {
1100
do_containerconts(box->cobj, identified, TRUE,
1103
container_contents(box->cobj, identified, TRUE);
1104
#endif /* DUMP_LOG */
1107
pline("%s empty.", Tobjnam(box, "are"));
1108
display_nhwindow(WIN_MESSAGE, FALSE);
1111
dump(The(xname(box)), " is empty.");
1117
if (!all_containers)
1123
/* should be called with either EXIT_SUCCESS or EXIT_FAILURE */
1129
getreturn("to exit");
1131
/* don't bother to try to release memory if we're in panic mode, to
1132
avoid trouble in case that happens to be due to memory problems */
1133
if (!program_state.panicking) {
1138
nethack_exit(status);
1142
list_vanquished(defquery, ask)
1147
do_vanquished(defquery, ask, FALSE);
1151
do_vanquished(defquery, ask, want_dump)
1157
register int i, lev;
1158
int ntypes = 0, max_lev = 0, nkilled;
1159
long total_killed = 0L;
1164
/* get totals first */
1165
for (i = LOW_PM; i < NUMMONS; i++) {
1166
if (mvitals[i].died) ntypes++;
1167
total_killed += (long)mvitals[i].died;
1168
if (mons[i].mlevel > max_lev) max_lev = mons[i].mlevel;
1171
/* vanquished creatures list;
1172
* includes all dead monsters, not just those killed by the player
1175
c = ask ? yn_function("Do you want an account of creatures vanquished?",
1176
ynqchars, defquery) : defquery;
1177
if (c == 'q') done_stopprint++;
1179
klwin = create_nhwindow(NHW_MENU);
1180
putstr(klwin, 0, "Vanquished creatures:");
1181
putstr(klwin, 0, "");
1183
if (want_dump) dump("", "Vanquished creatures");
1186
/* countdown by monster "toughness" */
1187
for (lev = max_lev; lev >= 0; lev--)
1188
for (i = LOW_PM; i < NUMMONS; i++)
1189
if (mons[i].mlevel == lev && (nkilled = mvitals[i].died) > 0) {
1190
if ((mons[i].geno & G_UNIQ) && i != PM_HIGH_PRIEST) {
1191
Sprintf(buf, "%s%s",
1192
!type_is_pname(&mons[i]) ? "The " : "",
1196
case 2: Sprintf(eos(buf)," (twice)"); break;
1197
case 3: Sprintf(eos(buf)," (thrice)"); break;
1198
default: Sprintf(eos(buf)," (%d time%s)",
1199
nkilled, plur(nkilled));
1204
/* trolls or undead might have come back,
1205
but we don't keep track of that */
1207
Strcpy(buf, an(mons[i].mname));
1209
Sprintf(buf, "%d %s",
1210
nkilled, makeplural(mons[i].mname));
1212
putstr(klwin, 0, buf);
1214
if (want_dump) dump(" ", buf);
1218
* if (Hallucination)
1219
* putstr(klwin, 0, "and a partridge in a pear tree");
1222
putstr(klwin, 0, "");
1223
Sprintf(buf, "%ld creatures vanquished.", total_killed);
1224
putstr(klwin, 0, buf);
1226
if (want_dump) dump(" ", buf);
1229
display_nhwindow(klwin, TRUE);
1230
destroy_nhwindow(klwin);
1232
if (want_dump) dump("", "");
1238
/* number of monster species which have been genocided */
1244
for (i = LOW_PM; i < NUMMONS; ++i)
1245
if (mvitals[i].mvflags & G_GENOD) ++n;
1252
list_genocided(defquery, ask, want_dump)
1258
list_genocided(defquery, ask)
1269
ngenocided = num_genocides();
1271
/* genocided species list */
1272
if (ngenocided != 0) {
1273
c = ask ? yn_function("Do you want a list of species genocided?",
1274
ynqchars, defquery) : defquery;
1275
if (c == 'q') done_stopprint++;
1277
klwin = create_nhwindow(NHW_MENU);
1278
Sprintf(buf, "Genocided species:");
1279
putstr(klwin, 0, buf);
1280
putstr(klwin, 0, "");
1282
if (want_dump) dump("", buf);
1285
for (i = LOW_PM; i < NUMMONS; i++)
1286
if (mvitals[i].mvflags & G_GENOD) {
1287
if ((mons[i].geno & G_UNIQ) && i != PM_HIGH_PRIEST)
1288
Sprintf(buf, "%s%s",
1289
!type_is_pname(&mons[i]) ? "" : "the ",
1292
Strcpy(buf, makeplural(mons[i].mname));
1293
putstr(klwin, 0, buf);
1295
if (want_dump) dump(" ", buf);
1299
putstr(klwin, 0, "");
1300
Sprintf(buf, "%d species genocided.", ngenocided);
1301
putstr(klwin, 0, buf);
1303
if (want_dump) dump(" ", buf);
1306
display_nhwindow(klwin, TRUE);
1307
destroy_nhwindow(klwin);