Logo Search packages:      
Sourcecode: falconseye version File versions  Download package

end.c

/*    SCCS Id: @(#)end.c      3.3   2000/06/10  */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed.  See license for details. */

#define NEED_VARARGS    /* comment line for pre-compiled headers */

#include "hack.h"
#include "eshk.h"
#ifndef NO_SIGNAL
#include <signal.h>
#endif
#include "dlb.h"


      /* these probably ought to be generated by makedefs, like LAST_GEM */
#define FIRST_GEM    DILITHIUM_CRYSTAL
#define FIRST_AMULET AMULET_OF_ESP
#define LAST_AMULET  AMULET_OF_YENDOR
 
struct valuable_data { long count; int typ; };

struct valuable_data
      gems[LAST_GEM+1 - FIRST_GEM + 1], /* 1 extra for glass */
      amulets[LAST_AMULET+1 - FIRST_AMULET];

static struct val_list { struct valuable_data *list; int size; } valuables[] = {
      { gems,    sizeof gems / sizeof *gems },
      { amulets, sizeof amulets / sizeof *amulets },
      { 0, 0 }
};

#ifndef NO_SIGNAL
STATIC_PTR void FDECL(done_intr, (int));
# if defined(UNIX) || defined(VMS) || defined (__EMX__)
static void FDECL(done_hangup, (int));
# endif
#endif
STATIC_DCL void FDECL(disclose,(int,BOOLEAN_P));
STATIC_DCL void FDECL(get_valuables, (struct obj *));
STATIC_DCL void FDECL(sort_valuables, (struct valuable_data *,int));
STATIC_DCL void FDECL(add_artifact_score, (struct obj *));
STATIC_DCL void FDECL(display_artifact_score, (struct obj *,winid));
STATIC_DCL void FDECL(savelife, (int));
STATIC_DCL void NDECL(list_vanquished);
STATIC_DCL void NDECL(list_genocided);

#if defined(__BEOS__) || defined(MICRO) || defined(WIN32) || defined(OS2)
extern void FDECL(nethack_exit,(int));
#else
#define nethack_exit exit
#endif

#define done_stopprint program_state.stopprint

#ifdef AMIGA
void NDECL(clear_icon);
# define NH_abort()     Abort(0)
#else
# ifdef SYSV
# define NH_abort()     (void) abort()
# else
# define NH_abort()     abort()
# endif
#endif

/*
 * The order of these needs to match the macros in hack.h.
 */
static NEARDATA const char *deaths[] = {        /* the array of death */
      "died", "choked", "poisoned", "starvation", "drowning",
      "burning", "dissolving under the heat and pressure",
      "crushed", "turned to stone", "turned into slime",
      "genocided", "panic", "trickery",
      "quit", "escaped", "ascended"
};

static NEARDATA const char *ends[] = {          /* "when you..." */
      "died", "choked", "were poisoned", "starved", "drowned",
      "burned", "dissolved in the lava",
      "were crushed", "turned to stone", "turned into slime",
      "were genocided", "panicked", "were tricked",
      "quit", "escaped", "ascended"
};

extern const char *killed_by_prefix[];


/*ARGSUSED*/
void
done1(sig_unused)   /* called as signal() handler, so sent at least one arg */
int sig_unused;
{
#ifndef NO_SIGNAL
      (void) signal(SIGINT,SIG_IGN);
#endif
      if(flags.ignintr) {
#ifndef NO_SIGNAL
            (void) signal(SIGINT, (SIG_RET_TYPE) done1);
#endif
            clear_nhwindow(WIN_MESSAGE);
            curs_on_u();
            wait_synch();
            if(multi > 0) nomul(0);
      } else {
            (void)done2();
      }
}


/* "#quit" command or keyboard interrupt */
int
done2()
{
      if(yn("Really quit?") == 'n') {
#ifndef NO_SIGNAL
            (void) signal(SIGINT, (SIG_RET_TYPE) done1);
#endif
            clear_nhwindow(WIN_MESSAGE);
            curs_on_u();
            wait_synch();
            if(multi > 0) nomul(0);
            if(multi == 0) {
                u.uinvulnerable = FALSE;  /* avoid ctrl-C bug -dlc */
                u.usleep = 0;
            }
            return 0;
      }
#if defined(WIZARD) && (defined(UNIX) || defined(VMS) || defined(LATTICE))
      if(wizard) {
          int c;
# ifdef VMS
          const char *tmp = "Enter debugger?";
# else
#  ifdef LATTICE
          const char *tmp = "Create SnapShot?";
#  else
          const char *tmp = "Dump core?";
#  endif
# endif
          if ((c = ynq(tmp)) == 'y') {
            (void) signal(SIGINT, (SIG_RET_TYPE) done1);
            exit_nhwindows((char *)0);
            NH_abort();
          } else if (c == 'q') done_stopprint++;
      }
#endif
#ifndef LINT
      done(QUIT);
#endif
      return 0;
}

#ifndef NO_SIGNAL
/*ARGSUSED*/
STATIC_PTR void
done_intr(sig_unused) /* called as signal() handler, so sent at least one arg */
int sig_unused;
{
      done_stopprint++;
      (void) signal(SIGINT, SIG_IGN);
# if defined(UNIX) || defined(VMS)
      (void) signal(SIGQUIT, SIG_IGN);
# endif
      return;
}

# if defined(UNIX) || defined(VMS) || defined(__EMX__)
static void
done_hangup(sig)  /* signal() handler */
int sig;
{
      program_state.done_hup++;
      (void)signal(SIGHUP, SIG_IGN);
      done_intr(sig);
      return;
}
# endif
#endif /* NO_SIGNAL */

void
done_in_by(mtmp)
register struct monst *mtmp;
{
      char buf[BUFSZ];
      boolean distorted = (boolean)(Hallucination && canspotmon(mtmp));

      You("die...");
      mark_synch();     /* flush buffered screen output */
      buf[0] = '\0';
      if ((mtmp->data->geno & G_UNIQ) != 0) {
          if (!type_is_pname(mtmp->data))
            Strcat(buf, "the ");
          killer_format = KILLED_BY;
      }
      if (mtmp->minvis)
            Strcat(buf, "invisible ");
      if (distorted)
            Strcat(buf, "hallucinogen-distorted ");

      if(mtmp->data == &mons[PM_GHOST]) {
            char *gn = NAME(mtmp);
            if (!distorted && !mtmp->minvis && *gn) {
                  Strcat(buf, "the ");
                  killer_format = KILLED_BY;
            }
            Sprintf(eos(buf), (*gn ? "ghost of %s" : "ghost%s"), gn);
      } else if(mtmp->isshk) {
            Sprintf(eos(buf), "%s %s, the shopkeeper",
                  (mtmp->female ? "Ms." : "Mr."), shkname(mtmp));
            killer_format = KILLED_BY;
      } else if (mtmp->ispriest || mtmp->isminion) {
            /* m_monnam() suppresses "the" prefix plus "invisible", and
               it overrides the effect of Hallucination on priestname() */
            killer = m_monnam(mtmp);
            Strcat(buf, killer);
      } else {
            Strcat(buf, mtmp->data->mname);
            if (mtmp->mnamelth)
                Sprintf(eos(buf), " called %s", NAME(mtmp));
      }

      if (multi) Strcat(buf, ", while helpless");
      killer = buf;
      if (mtmp->data->mlet == S_WRAITH)
            u.ugrave_arise = PM_WRAITH;
      else if (mtmp->data->mlet == S_MUMMY && urace.mummynum != NON_PM)
            u.ugrave_arise = urace.mummynum;
      else if (mtmp->data->mlet == S_VAMPIRE && Race_if(PM_HUMAN))
            u.ugrave_arise = PM_VAMPIRE;
      if (u.ugrave_arise >= LOW_PM &&
                        (mvitals[u.ugrave_arise].mvflags & G_GENOD))
            u.ugrave_arise = NON_PM;
      if (touch_petrifies(mtmp->data))
            done(STONING);
      else
            done(DIED);
      return;
}

/*VARARGS1*/
void
panic VA_DECL(const char *, str)
      VA_START(str);
      VA_INIT(str, char *);

      if (program_state.panicking++)
          NH_abort();   /* avoid loops - this should never happen*/

      if (iflags.window_inited) {
          raw_print("\r\nOops...");
          wait_synch(); /* make sure all pending output gets flushed */
          exit_nhwindows((char *)0);
          iflags.window_inited = 0; /* they're gone; force raw_print()ing */
      }

      raw_print(!program_state.something_worth_saving ?
              "Program initialization has failed." :
              "Suddenly, the dungeon collapses.");
#if defined(WIZARD) && !defined(MICRO)
      if (!wizard)
          raw_printf("Report error to \"%s\"%s.",
# ifdef WIZARD_NAME     /*(KR1ED)*/
                  WIZARD_NAME,
# else
                  WIZARD,
# endif
                  !program_state.something_worth_saving ? "" :
                  " and it may be possible to rebuild.");
      if (program_state.something_worth_saving) {
          set_error_savefile();
          (void) dosave0();
      }
#endif
      {
          char buf[BUFSZ];
          Vsprintf(buf,str,VA_ARGS);
          raw_print(buf);
      }
#if defined(WIZARD) && (defined(UNIX) || defined(VMS) || defined(LATTICE))
      if (wizard)
          NH_abort();   /* generate core dump */
#endif
      VA_END();
      done(PANICKED);
}

STATIC_OVL void
disclose(how,taken)
int how;
boolean taken;
{
      char  c;
      char  qbuf[QBUFSZ];

      if (invent && !done_stopprint &&
            (!flags.end_disclose[0] || index(flags.end_disclose, 'i'))) {
          if(taken)
            Sprintf(qbuf,"Do you want to see what you had when you %s?",
                  (how == QUIT) ? "quit" : "died");
          else
            Strcpy(qbuf,"Do you want your possessions identified?");
          if ((c = yn_function(qbuf, ynqchars, 'y')) == 'y') {
          /* New dump format by maartenj@cs.vu.nl */
            struct obj *obj;

            for (obj = invent; obj; obj = obj->nobj) {
                makeknown(obj->otyp);
                obj->known = obj->bknown = obj->dknown = obj->rknown = 1;
            }
            (void) display_inventory((char *)0, TRUE);
            container_contents(invent, TRUE, TRUE);
          }
          if (c == 'q')  done_stopprint++;
      }

      if (!done_stopprint &&
            (!flags.end_disclose[0] || index(flags.end_disclose, 'a'))) {
          c = yn_function("Do you want to see your attributes?",ynqchars,'y');
          if (c == 'y') enlightenment(how >= PANICKED ? 1 : 2); /* final */
          if (c == 'q') done_stopprint++;
      }

      if (!done_stopprint &&
            (!flags.end_disclose[0] || index(flags.end_disclose, 'v'))) {
          list_vanquished();
      }

      if (!done_stopprint &&
            (!flags.end_disclose[0] || index(flags.end_disclose, 'g'))) {
          list_genocided();
      }

      if (!done_stopprint &&
            (!flags.end_disclose[0] || index(flags.end_disclose, 'c'))) {
          c = yn_function("Do you want to see your conduct?",ynqchars,'y');
          if (c == 'y') show_conduct(how >= PANICKED ? 1 : 2);
          if (c == 'q') done_stopprint++;
      }
}

/* try to get the player back in a viable state after being killed */
STATIC_OVL void
savelife(how)
int how;
{
      u.uswldtim = 0;
      u.uhp = u.uhpmax;
      if (u.uhunger < 500) {
          u.uhunger = 500;
          newuhs(FALSE);
      }
      if (how == CHOKING) init_uhunger();
      nomovemsg = "You survived that attempt on your life.";
      flags.move = 0;
      if(multi > 0) multi = 0; else multi = -1;
      if(u.utrap && u.utraptype == TT_LAVA) u.utrap = 0;
      flags.botl = 1;
      u.ugrave_arise = NON_PM;
      HUnchanging = 0L;
      curs_on_u();
}

/*
 * Get valuables from the given list.  Revised code: the list always remains
 * intact.
 */
STATIC_OVL void
get_valuables(list)
struct obj *list; /* inventory or container contents */
{
    register struct obj *obj;
    register int i;

    /* find amulets and gems, ignoring artifacts except for the AoY. */
    for (obj = list; obj; obj = obj->nobj)
      if (Has_contents(obj)) {
          get_valuables(obj->cobj);
      } else if (obj->oclass == AMULET_CLASS) {
          i = obj->otyp - FIRST_AMULET;
          if (!amulets[i].count) {
            amulets[i].count = obj->quan;
            amulets[i].typ = obj->otyp;
          } else amulets[i].count += obj->quan; /* always adds one */
      } else if (obj->oclass == GEM_CLASS && obj->otyp < LUCKSTONE &&
            !obj->oartifact) {
          i = min(obj->otyp, LAST_GEM + 1) - FIRST_GEM;
          if (!gems[i].count) {
            gems[i].count = obj->quan;
            gems[i].typ = obj->otyp;
          } else gems[i].count += obj->quan;
      }
    return;
}

/*
 *  Sort collected valuables, most frequent to least.  We could just
 *  as easily use qsort, but we don't care about efficiency here.
 */
STATIC_OVL void
sort_valuables(list, size)
struct valuable_data list[];
int size;         /* max value is less than 20 */
{
    register int i, j;
    struct valuable_data ltmp;

    /* move greater quantities to the front of the list */
    for (i = 1; i < size; i++) {
      if (list[i].count == 0) continue;   /* empty slot */
      ltmp = list[i]; /* structure copy */
      for (j = i; j > 0; --j)
          if (list[j-1].count >= ltmp.count) break;
          else {
            list[j] = list[j-1];
          }
      list[j] = ltmp;
    }
    return;
}

STATIC_OVL void
add_artifact_score(list)
struct obj *list;
{
    struct obj *otmp;

    for (otmp = list; otmp; otmp = otmp->nobj)
      if (otmp->oartifact ||
                  otmp->otyp == BELL_OF_OPENING ||
                  otmp->otyp == SPE_BOOK_OF_THE_DEAD ||
                  otmp->otyp == CANDELABRUM_OF_INVOCATION) {
          /* shopkeepers charge 100x; 250x is arbitrary */
          u.urexp += 250L * (long)objects[otmp->otyp].oc_cost;
      if (Has_contents(otmp))
          add_artifact_score(otmp->cobj);
    }
}

STATIC_OVL void
display_artifact_score(list,endwin)
struct obj *list;
winid endwin;
{
    char pbuf[BUFSZ];
    struct obj *otmp;

    for (otmp = list; otmp; otmp = otmp->nobj) {
      if (otmp->oartifact ||
                  otmp->otyp == BELL_OF_OPENING ||
                  otmp->otyp == SPE_BOOK_OF_THE_DEAD ||
                  otmp->otyp == CANDELABRUM_OF_INVOCATION) {
          short dummy;

          makeknown(otmp->otyp);
          otmp->known = otmp->bknown = otmp->dknown =
            otmp->rknown = 1;
          /* assumes artifacts don't have quan>1 */
          Sprintf(pbuf, "%s (worth %ld zorkmids and %ld points)",
            otmp->oartifact ? artifact_name(xname(otmp), &dummy) :
                  OBJ_NAME(objects[otmp->otyp]),
            100L * (long)objects[otmp->otyp].oc_cost,
            250L * (long)objects[otmp->otyp].oc_cost);
          putstr(endwin, 0, pbuf);
      }
      if (Has_contents(otmp))
          display_artifact_score(otmp->cobj,endwin);
    }
}

/* Be careful not to call panic from here! */
void
done(how)
int how;
{
      boolean taken;
      char kilbuf[BUFSZ], pbuf[BUFSZ];
      winid endwin = WIN_ERR;
      boolean bones_ok, have_windows = iflags.window_inited;
      struct obj *corpse = (struct obj *)0;

      /* kilbuf: used to copy killer in case it comes from something like
       *    xname(), which would otherwise get overwritten when we call
       *    xname() when listing possessions
       * pbuf: holds Sprintf'd output for raw_print and putstr
       */
      if (how == ASCENDED)
            killer_format = NO_KILLER_PREFIX;
      /* Avoid killed by "a" burning or "a" starvation */
      if (!killer && (how == STARVING || how == BURNING))
            killer_format = KILLED_BY;
      Strcpy(kilbuf, (!killer || how >= PANICKED ? deaths[how] : killer));
      killer = kilbuf;
#ifdef WIZARD
      if (wizard && how == TRICKED) {
            You("are a very tricky wizard, it seems.");
            return;
      }
#endif
      if (how < PANICKED) u.umortality++;
      if (Lifesaved && (how <= GENOCIDED)) {
            pline("But wait...");
            makeknown(AMULET_OF_LIFE_SAVING);
            Your("medallion %s!",
                  !Blind ? "begins to glow" : "feels warm");
            if (how == CHOKING) You("vomit ...");
            You_feel("much better!");
            pline_The("medallion crumbles to dust!");
            if (uamul) useup(uamul);

            (void) adjattrib(A_CON, -1, TRUE);
            if(u.uhpmax <= 0) u.uhpmax = 10;    /* arbitrary */
            savelife(how);
            if (how == GENOCIDED)
                  pline("Unfortunately you are still genocided...");
            else {
                  killer = 0;
                  killer_format = 0;
                  return;
            }
      }
      if ((
#ifdef WIZARD
                  wizard ||
#endif
                  discover) && (how <= GENOCIDED)) {
            if(yn("Die?") == 'y') goto die;
            pline("OK, so you don't %s.",
                  (how == CHOKING) ? "choke" : "die");
            if(u.uhpmax <= 0) u.uhpmax = u.ulevel * 8;      /* arbitrary */
            savelife(how);
            killer = 0;
            killer_format = 0;
            return;
      }

    /*
     *      The game is now over...
     */

die:
      program_state.gameover = 1;
      /* in case of a subsequent panic(), there's no point trying to save */
      program_state.something_worth_saving = 0;
      /* turn off vision subsystem */
      vision_recalc(2);
      /* might have been killed while using a disposable item, so make sure
         it's gone prior to inventory disclosure and creation of bones data */
      inven_inuse(TRUE);

      /* Sometimes you die on the first move.  Life's not fair.
       * On those rare occasions you get hosed immediately, go out
       * smiling... :-)  -3.
       */
      if (moves <= 1 && how < PANICKED)   /* You die... --More-- */
          pline("Do not pass go.  Do not collect 200 zorkmids.");

      if (have_windows) wait_synch();     /* flush screen output */
#ifndef NO_SIGNAL
      (void) signal(SIGINT, (SIG_RET_TYPE) done_intr);
# if defined(UNIX) || defined(VMS) || defined (__EMX__)
      (void) signal(SIGQUIT, (SIG_RET_TYPE) done_intr);
      (void) signal(SIGHUP, (SIG_RET_TYPE) done_hangup);
# endif
#endif /* NO_SIGNAL */

      bones_ok = (how < GENOCIDED) && can_make_bones();

      if (how == TURNED_SLIME)
          u.ugrave_arise = PM_GREEN_SLIME;

      if (bones_ok && u.ugrave_arise < LOW_PM) {
          /* corpse gets burnt up too */
          if (how == BURNING)
            u.ugrave_arise = (NON_PM - 2);      /* leave no corpse */
          else if (how == STONING)
            u.ugrave_arise = (NON_PM - 1);      /* statue instead of corpse */
          else if (u.ugrave_arise == NON_PM) {
            corpse = mk_named_object(CORPSE, &mons[u.umonnum],
                               u.ux, u.uy, plname);
            Sprintf(pbuf, "%s, %s%s", plname,
                  killer_format == NO_KILLER_PREFIX ? "" :
                  killed_by_prefix[how],
                  killer_format == KILLED_BY_AN ? an(killer) : killer);
            make_grave(u.ux, u.uy, pbuf);
          }
      }

      if (how == QUIT) {
            killer_format = NO_KILLER_PREFIX;
            if (u.uhp < 1) {
                  how = DIED;
                  u.umortality++;   /* skipped above when how==QUIT */
                  /* note that killer is pointing at kilbuf */
                  Strcpy(kilbuf, "quit while already on Charon's boat");
            }
      }
      if (how == ESCAPED || how == PANICKED)
            killer_format = NO_KILLER_PREFIX;

      if (how != PANICKED) {
          /* these affect score and/or bones, but avoid them during panic */
          taken = paybill(how != QUIT);
          paygd();
          clearpriests();
      } else      taken = FALSE;    /* lint; assert( !bones_ok ); */

      clearlocks();
#ifdef AMIGA
      clear_icon();
#endif
      if (have_windows) display_nhwindow(WIN_MESSAGE, FALSE);

      if (strcmp(flags.end_disclose, "none") && how != PANICKED)
            disclose(how, taken);
            
      /* finish_paybill should be called after disclosure but before bones */
      if (bones_ok && taken) finish_paybill();

      /* calculate score, before creating bones [container gold] */
      {
          long tmp;
          int deepest = deepest_lev_reached(FALSE);

          u.ugold += hidden_gold(); /* accumulate gold from containers */
          tmp = u.ugold - u.ugold0;
          if (tmp < 0L)
            tmp = 0L;
          if (how < PANICKED)
            tmp -= tmp / 10L;
          u.urexp += tmp;
          u.urexp += 50L * (long)(deepest - 1);
          if (deepest > 20)
            u.urexp += 1000L * (long)((deepest > 30) ? 10 : deepest - 20);
          if (how == ASCENDED) u.urexp *= 2L;
      }

      if (bones_ok) {
#ifdef WIZARD
          if (!wizard || yn("Save bones?") == 'y')
#endif
            savebones(corpse);
          /* corpse may be invalid pointer now so
            ensure that it isn't used again */
          corpse = (struct obj *)0;
      }

      /* clean up unneeded windows */
      if (have_windows) {
          wait_synch();
          display_nhwindow(WIN_MESSAGE, TRUE);
          destroy_nhwindow(WIN_MAP);
          destroy_nhwindow(WIN_STATUS);
          destroy_nhwindow(WIN_MESSAGE);
          WIN_MESSAGE = WIN_STATUS = WIN_MAP = WIN_ERR;

          if(!done_stopprint || flags.tombstone)
          {
            endwin = create_nhwindow(NHW_TEXT);       
          }

#ifdef JTP_GRAPHICS
          if (strcmp(windowprocs.name, "jtp") == 0)
            outrip(endwin, how);
          else  
#endif
          if(how < GENOCIDED && flags.tombstone)
          {
            outrip(endwin, how);
          }           
      } else
          done_stopprint = 1; /* just avoid any more output */

/* changing kilbuf really changes killer. we do it this way because
   killer is declared a (const char *)
*/
      if (u.uhave.amulet) Strcat(kilbuf, " (with the Amulet)");
      else if (how == ESCAPED) {
          if (Is_astralevel(&u.uz)) /* offered Amulet to wrong deity */
            Strcat(kilbuf, " (in celestial disgrace)");
          else if (carrying(FAKE_AMULET_OF_YENDOR))
            Strcat(kilbuf, " (with a fake Amulet)");
            /* don't bother counting to see whether it should be plural */
      }

      if (!done_stopprint) {
          Sprintf(pbuf, "%s %s the %s...", Goodbye(), plname,
               how != ASCENDED ?
                  (const char *) ((flags.female && urole.name.f) ?
                     urole.name.f : urole.name.m) :
                  (const char *) (flags.female ? "Demigoddess" : "Demigod"));
          putstr(endwin, 0, pbuf);
          putstr(endwin, 0, "");
      }

      if (how == ESCAPED || how == ASCENDED) {
          register struct monst *mtmp;
          register struct obj *otmp;
          register struct val_list *val;
          register int i;

          for (val = valuables; val->list; val++)
            for (i = 0; i < val->size; i++) {
                val->list[i].count = 0L;
            }
          get_valuables(invent);

          /* add points for collected valuables */
          for (val = valuables; val->list; val++)
            for (i = 0; i < val->size; i++)
                if (val->list[i].count != 0L)
                  u.urexp += val->list[i].count
                          * (long)objects[val->list[i].typ].oc_cost;

          add_artifact_score(invent);

          keepdogs(TRUE);
          viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */
          mtmp = mydogs;
          if (!done_stopprint) Strcpy(pbuf, "You");
          if (mtmp) {
            while (mtmp) {
                if (!done_stopprint)
                  Sprintf(eos(pbuf), " and %s", mon_nam(mtmp));
                if (mtmp->mtame)
                  u.urexp += mtmp->mhp;
                mtmp = mtmp->nmon;
            }
            if (!done_stopprint) putstr(endwin, 0, pbuf);
            pbuf[0] = '\0';
          } else {
            if (!done_stopprint) Strcat(pbuf, " ");
          }
          if (!done_stopprint) {
            Sprintf(eos(pbuf), "%s with %ld point%s,",
                  how==ASCENDED ? "went to your reward" :
                              "escaped from the dungeon",
                  u.urexp, plur(u.urexp));
            putstr(endwin, 0, pbuf);
          }

          if (!done_stopprint)
            display_artifact_score(invent,endwin);

          /* list valuables here */
          for (val = valuables; val->list; val++) {
            sort_valuables(val->list, val->size);
            for (i = 0; i < val->size && !done_stopprint; i++) {
                int typ = val->list[i].typ;
                long count = val->list[i].count;

                if (count == 0L) continue;
                if (objects[typ].oc_class != GEM_CLASS || typ <= LAST_GEM) {
                  otmp = mksobj(typ, FALSE, FALSE);
                  makeknown(otmp->otyp);
                  otmp->known = 1;  /* for fake amulets */
                  otmp->dknown = 1; /* seen it (blindness fix) */
                  otmp->onamelth = 0;
                  otmp->quan = count;
                  Sprintf(pbuf, "%8ld %s (worth %ld zorkmids),",
                        count, xname(otmp),
                        count * (long)objects[typ].oc_cost);
                  obfree(otmp, (struct obj *)0);
                } else {
                  Sprintf(pbuf,
                        "%8ld worthless piece%s of colored glass,",
                        count, plur(count));
                }
                putstr(endwin, 0, pbuf);
            }
          }

      } else if (!done_stopprint) {
          /* did not escape or ascend */
          
          if (u.uz.dnum == 0 && u.uz.dlevel <= 0) {
            /* level teleported out of the dungeon; `how' is DIED,
               due to falling or to "arriving at heaven prematurely" */
            Sprintf(pbuf, "You %s beyond the confines of the dungeon",
                  (u.uz.dlevel < 0) ? "passed away" : ends[how]);
          } else {
            /* more conventional demise */
            const char *where = dungeons[u.uz.dnum].dname;

            if (Is_astralevel(&u.uz)) where = "The Astral Plane";
            Sprintf(pbuf, "You %s in %s", ends[how], where);
            if (!In_endgame(&u.uz) && !Is_knox(&u.uz))
                Sprintf(eos(pbuf), " on dungeon level %d",
                      In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz));
          }

          Sprintf(eos(pbuf), " with %ld point%s,",
                u.urexp, plur(u.urexp));
          putstr(endwin, 0, pbuf);
      }

      if (!done_stopprint) {
          Sprintf(pbuf, "and %ld piece%s of gold, after %ld move%s.",
                u.ugold, plur(u.ugold), moves, plur(moves));
          putstr(endwin, 0, pbuf);
      }
      if (!done_stopprint) {
          Sprintf(pbuf,
           "You were level %d with a maximum of %d hit point%s when you %s.",
                u.ulevel, u.uhpmax, plur(u.uhpmax), ends[how]);
          putstr(endwin, 0, pbuf);
          putstr(endwin, 0, "");
      }
      if (!done_stopprint)
          display_nhwindow(endwin, TRUE);
      if (endwin != WIN_ERR)
          destroy_nhwindow(endwin);

      /* "So when I die, the first thing I will see in Heaven is a
       * score list?" */
      if (flags.toptenwin) {
          topten(how);
          if (have_windows)
            exit_nhwindows((char *)0);
      } else {
          if (have_windows)
            exit_nhwindows((char *)0);
          topten(how);
      }

      if(done_stopprint) { raw_print(""); raw_print(""); }
      terminate(EXIT_SUCCESS);
}


void
container_contents(list, identified, all_containers)
struct obj *list;
boolean identified, all_containers;
{
      register struct obj *box, *obj;
      char buf[BUFSZ];

      for (box = list; box; box = box->nobj) {
          if (Is_container(box) && box->otyp != BAG_OF_TRICKS) {
            if (box->cobj) {
                winid tmpwin = create_nhwindow(NHW_MENU);
                Sprintf(buf, "Contents of %s:", the(xname(box)));
                putstr(tmpwin, 0, buf);
                putstr(tmpwin, 0, "");
                for (obj = box->cobj; obj; obj = obj->nobj) {
                  if (identified) {
                      makeknown(obj->otyp);
                      obj->known = obj->bknown =
                      obj->dknown = obj->rknown = 1;
                  }
                  putstr(tmpwin, 0, doname(obj));
                }
                display_nhwindow(tmpwin, TRUE);
                destroy_nhwindow(tmpwin);
                if (all_containers)
                  container_contents(box->cobj, identified, TRUE);
            } else {
                pline("%s is empty.", The(xname(box)));
                display_nhwindow(WIN_MESSAGE, FALSE);
            }
          }
          if (!all_containers)
            break;
      }
}


/* should be called with either EXIT_SUCCESS or EXIT_FAILURE */
void
terminate(status)
int status;
{
#ifdef MAC
      getreturn("to exit");
#endif
      /* don't bother to try to release memory if we're in panic mode, to
         avoid trouble in case that happens to be due to memory problems */
      if (!program_state.panicking) {
          freedynamicdata();
          dlb_cleanup();
      }

      nethack_exit(status);
}

STATIC_OVL void
list_vanquished()
{
    register int i, lev;
    int ntypes = 0, max_lev = 0, nkilled;
    long total_killed = 0L;
    char c;
    winid klwin;
    char buf[BUFSZ];

    /* get totals first */
    for (i = LOW_PM; i < NUMMONS; i++) {
      if (mvitals[i].died) ntypes++;
      total_killed += (long)mvitals[i].died;
      if (mons[i].mlevel > max_lev) max_lev = mons[i].mlevel;
    }

    /* vanquished creatures list;
     * includes all dead monsters, not just those killed by the player
     */
    if (ntypes != 0) {
      c = yn_function("Do you want an account of creatures vanquished?",
                  ynqchars, 'n');
      if (c == 'q') done_stopprint++;
      if (c == 'y') {
          klwin = create_nhwindow(NHW_MENU);
          putstr(klwin, 0, "Vanquished creatures:");
          putstr(klwin, 0, "");

          /* countdown by monster "toughness" */
          for (lev = max_lev; lev >= 0; lev--)
            for (i = LOW_PM; i < NUMMONS; i++)
            if (mons[i].mlevel == lev && (nkilled = mvitals[i].died) > 0) {
                if ((mons[i].geno & G_UNIQ) && i != PM_HIGH_PRIEST) {
                  Sprintf(buf, "%s%s",
                        !type_is_pname(&mons[i]) ? "The " : "",
                        mons[i].mname);
                  if (nkilled > 1)
                      Sprintf(eos(buf)," (%d time%s)",
                            nkilled, plur(nkilled));
                } else {
                  /* trolls or undead might have come back,
                     but we don't keep track of that */
                  if (nkilled == 1)
                      Strcpy(buf, an(mons[i].mname));
                  else
                      Sprintf(buf, "%d %s",
                            nkilled, makeplural(mons[i].mname));
                }
                putstr(klwin, 0, buf);
            }
          /*
           * if (Hallucination)
           *     putstr(klwin, 0, "and a partridge in a pear tree");
           */
          if (ntypes > 1) {
            putstr(klwin, 0, "");
            Sprintf(buf, "%ld creatures vanquished.", total_killed);
            putstr(klwin, 0, buf);
          }
          display_nhwindow(klwin, TRUE);
          destroy_nhwindow(klwin);
      }
    }
}

/* number of monster species which have been genocided */
int
num_genocides()
{
    int i, n = 0;

    for (i = LOW_PM; i < NUMMONS; ++i)
      if (mvitals[i].mvflags & G_GENOD) ++n;

    return n;
}

STATIC_OVL void
list_genocided()
{
    register int i;
    int ngenocided;
    char c;
    winid klwin;
    char buf[BUFSZ];

    ngenocided = num_genocides();

    /* genocided species list */
    if (ngenocided != 0) {
      c = yn_function("Do you want a list of species genocided?",
                  ynqchars, 'n');
      if (c == 'q') done_stopprint++;
      if (c == 'y') {
          klwin = create_nhwindow(NHW_MENU);
          putstr(klwin, 0, "Genocided species:");
          putstr(klwin, 0, "");

          for (i = LOW_PM; i < NUMMONS; i++)
            if (mvitals[i].mvflags & G_GENOD) {
                if ((mons[i].geno & G_UNIQ) && i != PM_HIGH_PRIEST)
                  Sprintf(buf, "%s%s",
                        !type_is_pname(&mons[i]) ? "" : "the ",
                        mons[i].mname);
                else
                  Strcpy(buf, makeplural(mons[i].mname));
                putstr(klwin, 0, buf);
            }

          putstr(klwin, 0, "");
          Sprintf(buf, "%d species genocided.", ngenocided);
          putstr(klwin, 0, buf);

          display_nhwindow(klwin, TRUE);
          destroy_nhwindow(klwin);
      }
    }
}

/*end.c*/

Generated by  Doxygen 1.6.0   Back to index