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

topten.c

/*    SCCS Id: @(#)topten.c   3.2   96/05/25    */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed.  See license for details. */

/*
**    Japanese version Copyright
**    (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000
**    changing point is marked `JP' (94/6/7)
**    JNetHack may be freely redistributed.  See license for details. 
*/

/*
      Y2K problem fixed
      by Issei Numata         1 Nov, 1999 
 */

#include "hack.h"
#include "dlb.h"
#ifdef SHORT_FILENAMES
#include "patchlev.h"
#else
#include "patchlevel.h"
#endif

#ifdef NH_EXTENSION_REPORT    /* jp */
extern int report_flag;       /* end.c で定義 */
#endif

#ifdef VMS
 /* We don't want to rewrite the whole file, because that entails  */
 /* creating a new version which requires that the old one be deletable. */
# define UPDATE_RECORD_IN_PLACE
#endif

/*
 * Updating in place can leave junk at the end of the file in some
 * circumstances (if it shrinks and the O.S. doesn't have a straightforward
 * way to truncate it).  The trailing junk is harmless and the code
 * which reads the scores will ignore it.
 */
#ifdef UPDATE_RECORD_IN_PLACE
static long final_fpos;
#endif

#define done_stopprint program_state.stopprint

#define newttentry() (struct toptenentry *) alloc(sizeof(struct toptenentry))
#define dealloc_ttentry(ttent) free((genericptr_t) (ttent))
#define NAMSZ     10
#define DTHSZ     60
#define PERSMAX    3          /* entries per name/uid per char. allowed */
#define POINTSMIN 1     /* must be > 0 */
#define ENTRYMAX  100   /* must be >= 10 */

#if !defined(MICRO) && !defined(MAC)
#define PERS_IS_UID           /* delete for PERSMAX per name; now per uid */
#endif
struct toptenentry {
      struct toptenentry *tt_next;
#ifdef UPDATE_RECORD_IN_PLACE
      long fpos;
#endif
      long points;
      int deathdnum, deathlev;
      int maxlvl, hp, maxhp, deaths;
      int ver_major, ver_minor, patchlevel;
      long deathdate, birthdate;
      int uid;
      char plchar;
      char sex;
      char name[NAMSZ+1];
      char death[DTHSZ+1];
} *tt_head;

static void FDECL(topten_print, (const char *));
static void FDECL(topten_print_bold, (const char *));
static xchar FDECL(observable_depth, (d_level *));
static void NDECL(outheader);
/*JP
static void FDECL(outentry, (int,struct toptenentry *,BOOLEAN_P));
*/
static void FDECL(outentry, (int,struct toptenentry *,BOOLEAN_P,BOOLEAN_P));
static void FDECL(readentry, (FILE *,struct toptenentry *));
static void FDECL(writeentry, (FILE *,struct toptenentry *));
static void FDECL(free_ttlist, (struct toptenentry *));
static int FDECL(classmon, (CHAR_P,BOOLEAN_P));
static int FDECL(score_wanted,
            (BOOLEAN_P, int,struct toptenentry *,int,const char **,int));
#ifdef NO_SCAN_BRACK
static void FDECL(nsb_mung_line,(char*));
static void FDECL(nsb_unmung_line,(char*));
#endif

/* must fit with end.c; used in rip.c */
NEARDATA const char *killed_by_prefix[] = {
#if 0 /*JP*/
      "killed by ", "choked on ", "poisoned by ", "", "drowned in ",
      "", "dissolved in ", "crushed to death by ", "petrified by ", "",
      "", "",
      "", "", ""
#endif /*JP*/
      "に殺された", "で窒息した", "の毒で死んだ", "", "溺死した",
      "焼死した", "溶岩に溶けた", "押し潰された", "石化した", "死んだ", "虐殺された",
        "", "",
      "", "", ""
};

static winid toptenwin = WIN_ERR;

static void
topten_print(x)
const char *x;
{
     if (toptenwin == WIN_ERR)
        raw_print(x);
     else
        putstr(toptenwin, ATR_NONE, x);
}

static void
topten_print_bold(x)
const char *x;
{
     if (toptenwin == WIN_ERR)
        raw_print_bold(x);
     else
        putstr(toptenwin, ATR_BOLD, x);
}

static xchar
observable_depth(lev)
d_level *lev;
{
#if 0 /* if we ever randomize the order of the elemental planes, we
         must use a constant external representation in the record file */
      if (In_endgame(lev)) {
          if (Is_astralevel(lev))    return -5;
          else if (Is_waterlevel(lev)) return -4;
          else if (Is_firelevel(lev))      return -3;
          else if (Is_airlevel(lev))       return -2;
          else if (Is_earthlevel(lev)) return -1;
          else                 return 0;  /* ? */
      } else
#endif
          return depth(lev);
}

static void
readentry(rfile,tt)
FILE *rfile;
struct toptenentry *tt;
{
#ifdef NO_SCAN_BRACK
      static char *fmt = "%d %d %d %ld %d %d %d %d %d %d %ld %ld %d%*c%c%c %s %s%*c";
#else
      static char *fmt = "%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d %c%c %[^,],%[^\n]%*c";
#endif

#ifdef UPDATE_RECORD_IN_PLACE
      /* note: fscanf() below must read the record's terminating newline */
      final_fpos = tt->fpos = ftell(rfile);
#endif
#define TTFIELDS 17
      if(fscanf(rfile, fmt,
                  &tt->ver_major, &tt->ver_minor, &tt->patchlevel,
                  &tt->points, &tt->deathdnum, &tt->deathlev,
                  &tt->maxlvl, &tt->hp, &tt->maxhp, &tt->deaths,
                  &tt->deathdate, &tt->birthdate,
                  &tt->uid, &tt->plchar, &tt->sex,
                    tt->name, tt->death) != TTFIELDS){
#undef TTFIELDS
            tt->points = 0;
      }
      else {
#ifdef NO_SCAN_BRACK
            if(tt->points > 0) {
                  nsb_unmung_line(tt->name);
                  nsb_unmung_line(tt->death);
            }
#endif
      }

      /* check old score entries for Y2K problem and fix whenever found */
      if (tt->points > 0) {
            if (tt->birthdate < 19000000L) tt->birthdate += 19000000L;
            if (tt->deathdate < 19000000L) tt->deathdate += 19000000L;
      }
}

static void
writeentry(rfile,tt)
FILE *rfile;
struct toptenentry *tt;
{
#ifdef NO_SCAN_BRACK
      nsb_mung_line(tt->name);
      nsb_mung_line(tt->death);
      (void) fprintf(rfile,"%d %d %d %ld %d %d %d %d %d %d %ld %ld %d %c%c %s %s\n",
#else
      (void) fprintf(rfile,"%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d %c%c %s,%s\n",
#endif
            tt->ver_major, tt->ver_minor, tt->patchlevel,
            tt->points, tt->deathdnum, tt->deathlev,
            tt->maxlvl, tt->hp, tt->maxhp, tt->deaths,
            tt->deathdate, tt->birthdate,
            tt->uid, tt->plchar, tt->sex,
            onlyspace(tt->name) ? "_" : tt->name, tt->death);
#ifdef NO_SCAN_BRACK
      nsb_unmung_line(tt->name);
      nsb_unmung_line(tt->death);
#endif
}

static void
free_ttlist(tt)
struct toptenentry *tt;
{
      struct toptenentry *ttnext;

      while (tt->points > 0) {
            ttnext = tt->tt_next;
            dealloc_ttentry(tt);
            tt = ttnext;
      }
      dealloc_ttentry(tt);
}

void
topten(how)
int how;
{
      int uid = getuid();
      int rank, rank0 = -1, rank1 = 0;
      int occ_cnt = PERSMAX;
      register struct toptenentry *t0, *tprev;
      struct toptenentry *t1;
      FILE *rfile;
      register int flg = 0;
      boolean t0_used;
#ifdef LOGFILE
      FILE *lfile;
#endif /* LOGFILE */

/* Under DICE 3.0, this crashes the system consistently, apparently due to
 * corruption of *rfile somewhere.  Until I figure this out, just cut out
 * topten support entirely - at least then the game exits cleanly.  --AC
 */
#ifdef _DCC
      return;
#endif

      if (flags.toptenwin) {
          toptenwin = create_nhwindow(NHW_TEXT);
      }

#if defined(UNIX) || defined(VMS)
#define HUP if (!program_state.done_hup)
#else
#define HUP
#endif

#ifdef TOS
      restore_colors(); /* make sure the screen is black on white */
#endif
      /* create a new 'topten' entry */
      t0_used = FALSE;
      t0 = newttentry();
      /* deepest_lev_reached() is in terms of depth(), and reporting the
       * deepest level reached in the dungeon death occurred in doesn't
       * seem right, so we have to report the death level in depth() terms
       * as well (which also seems reasonable since that's all the player
       * sees on the screen anyway)
       */
      t0->ver_major = VERSION_MAJOR;
      t0->ver_minor = VERSION_MINOR;
      t0->patchlevel = PATCHLEVEL;
      t0->points = u.urexp;
      t0->deathdnum = u.uz.dnum;
      t0->deathlev = observable_depth(&u.uz);
      t0->maxlvl = deepest_lev_reached(TRUE);
      t0->hp = u.uhp;
      t0->maxhp = u.uhpmax;
      t0->deaths = u.umortality;
      t0->uid = uid;
      t0->plchar = pl_character[0];
      t0->sex = (flags.female ? 'F' : 'M');
      (void) strncpy(t0->name, plname, NAMSZ);
      if( is_kanji1(t0->name, NAMSZ-1) )  /* JP */
            t0->name[NAMSZ-1] = '_';
      t0->name[NAMSZ] = '\0';
      t0->death[0] = '\0';
      switch (killer_format) {
            default: impossible("bad killer format?");
            case KILLED_BY_AN:
/*JP              Strcat(t0->death, killed_by_prefix[how]);
                  (void) strncat(t0->death, an(killer),
                                    DTHSZ-strlen(t0->death));*/
                  (void) strncat(t0->death, an(killer),
                                    DTHSZ-strlen(t0->death));
                  Strcat(t0->death, killed_by_prefix[how]);
                  break;
            case KILLED_BY:
/*JP              Strcat(t0->death, killed_by_prefix[how]);
                  (void) strncat(t0->death, killer,
                                    DTHSZ-strlen(t0->death));*/
                  (void) strncat(t0->death, killer,
                                    DTHSZ-strlen(t0->death));
                  Strcat(t0->death, killed_by_prefix[how]);
                  break;
            case NO_KILLER_PREFIX:
                  (void) strncat(t0->death, killer, DTHSZ);
                  break;
      }
      t0->birthdate = yyyymmdd(u.ubirthday);
      t0->deathdate = yyyymmdd((time_t)0L);
      t0->tt_next = 0;
#ifdef UPDATE_RECORD_IN_PLACE
      t0->fpos = -1L;
#endif

#ifdef LOGFILE          /* used for debugging (who dies of what, where) */
      if (lock_file(LOGFILE, 10)) {
          if(!(lfile = fopen_datafile(LOGFILE,"a"))) {
            HUP raw_print("Cannot open log file!");
          } else {
            writeentry(lfile, t0);
            (void) fclose(lfile);
          }
          unlock_file(LOGFILE);
      }
#endif /* LOGFILE */

#if 1 /*バグ出しのため*/
      if (wizard || discover) {
          if (how != PANICKED) HUP {
            char pbuf[BUFSZ];
            topten_print("");
            Sprintf(pbuf,
/*JP        "Since you were in %s mode, the score list will not be checked.",
                wizard ? "wizard" : "discover");*/
            "%sモードでプレイしたのでスコアリストには載らない.",
                wizard ? "ウィザード" : "ディスカバリ");
            topten_print(pbuf);
          }
          goto showwin;
      }
#endif

      if (!lock_file(RECORD, 60))
            goto destroywin;

#ifdef UPDATE_RECORD_IN_PLACE
      rfile = fopen_datafile(RECORD, "r+");
#else
      rfile = fopen_datafile(RECORD, "r");
#endif

      if (!rfile) {
            HUP raw_print("Cannot open record file!");
            unlock_file(RECORD);
            goto destroywin;
      }

      HUP topten_print("");

      /* assure minimum number of points */
      if(t0->points < POINTSMIN) t0->points = 0;

      t1 = tt_head = newttentry();
      tprev = 0;
      /* rank0: -1 undefined, 0 not_on_list, n n_th on list */
      for(rank = 1; ; ) {
          readentry(rfile, t1);
          if (t1->points < POINTSMIN) t1->points = 0;
          if(rank0 < 0 && t1->points < t0->points) {
            rank0 = rank++;
            if(tprev == 0)
                  tt_head = t0;
            else
                  tprev->tt_next = t0;
            t0->tt_next = t1;
#ifdef UPDATE_RECORD_IN_PLACE
            t0->fpos = t1->fpos;    /* insert here */
#endif
            t0_used = TRUE;
            occ_cnt--;
            flg++;            /* ask for a rewrite */
          } else tprev = t1;

          if(t1->points == 0) break;
          if(
#ifdef PERS_IS_UID
            t1->uid == t0->uid &&
#else
            strncmp(t1->name, t0->name, NAMSZ) == 0 &&
#endif
            t1->plchar == t0->plchar && --occ_cnt <= 0) {
                if(rank0 < 0) {
                  rank0 = 0;
                  rank1 = rank;
                  HUP {
                      char pbuf[BUFSZ];
                      Sprintf(pbuf,
/*JP                "You didn't beat your previous score of %ld points.",*/
                    "あなたは以前の%ldポイントのスコアに届かなかった.",
                            t1->points);
                      topten_print(pbuf);
                      topten_print("");
                  }
                }
                if(occ_cnt < 0) {
                  flg++;
                  continue;
                }
            }
          if(rank <= ENTRYMAX) {
            t1->tt_next = newttentry();
            t1 = t1->tt_next;
            rank++;
          }
          if(rank > ENTRYMAX) {
            t1->points = 0;
            break;
          }
      }
      if(flg) {   /* rewrite record file */
#ifdef UPDATE_RECORD_IN_PLACE
            (void) fseek(rfile, (t0->fpos >= 0 ?
                             t0->fpos : final_fpos), SEEK_SET);
#else
            (void) fclose(rfile);
            if(!(rfile = fopen_datafile(RECORD,"w"))){
                  HUP raw_print("Cannot write record file");
                  unlock_file(RECORD);
                  free_ttlist(tt_head);
                  goto destroywin;
            }
#endif      /* UPDATE_RECORD_IN_PLACE */
            if(!done_stopprint) if(rank0 > 0){
                if(rank0 <= 10)
/*JP              topten_print("You made the top ten list!");*/
                  topten_print("あなたはトップ10リストに載った!");
                else {
                  char pbuf[BUFSZ];
                  Sprintf(pbuf,
/*JP                "You reached the %d%s place on the top %d list.",
                        rank0, ordin(rank0), ENTRYMAX);*/
                    "あなたは,トップ%dリストの%d位に載った!",
                        ENTRYMAX, rank0 );
                  topten_print(pbuf);
                }
                topten_print("");
            }
      }
      if(rank0 == 0) rank0 = rank1;
      if(rank0 <= 0) rank0 = rank;
      if(!done_stopprint) outheader();
      t1 = tt_head;
      for(rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
          if(flg
#ifdef UPDATE_RECORD_IN_PLACE
                && rank >= rank0
#endif
            ) writeentry(rfile, t1);
          if (done_stopprint) continue;
          if (rank > flags.end_top &&
                (rank < rank0 - flags.end_around ||
                 rank > rank0 + flags.end_around) &&
                (!flags.end_own ||
#ifdef PERS_IS_UID
                              t1->uid != t0->uid
#else
                              strncmp(t1->name, t0->name, NAMSZ)
#endif
            )) continue;
          if (rank == rank0 - flags.end_around &&
                rank0 > flags.end_top + flags.end_around + 1 &&
                !flags.end_own)
            topten_print("");
          if(rank != rank0)
            outentry(rank, t1, FALSE, FALSE);
          else if(!rank1)
            outentry(rank, t1, TRUE, TRUE);
          else {
            outentry(rank, t1, TRUE, FALSE);
            outentry(0, t0, TRUE, TRUE);
          }
      }
      if(rank0 >= rank) if(!done_stopprint)
            outentry(0, t0, TRUE, TRUE);
#ifdef UPDATE_RECORD_IN_PLACE
      if (flg) {
# ifdef TRUNCATE_FILE
          /* if a reasonable way to truncate a file exists, use it */
          truncate_file(rfile);
# else
          /* use sentinel record rather than relying on truncation */
          t1->points = 0L;    /* terminates file when read back in */
          t1->ver_major = t1->ver_minor = t1->patchlevel = 0;
          t1->uid = t1->deathdnum = t1->deathlev = 0;
          t1->maxlvl = t1->hp = t1->maxhp = t1->deaths = 0;
          t1->plchar = t1->sex = '-';
          t1->birthdate = t1->deathdate = yyyymmdd((time_t)0L);
          Strcpy(t1->name, "@");
          Strcpy(t1->death, "<eod>\n");
          writeentry(rfile, t1);
          (void) fflush(rfile);
# endif     /* TRUNCATE_FILE */
      }
#endif      /* UPDATE_RECORD_IN_PLACE */
      (void) fclose(rfile);
      unlock_file(RECORD);
      free_ttlist(tt_head);
  showwin:

      if (flags.toptenwin && !done_stopprint) display_nhwindow(toptenwin, 1);
  destroywin:
      if (!t0_used) dealloc_ttentry(t0);
      if (flags.toptenwin) {
          destroy_nhwindow(toptenwin);
          toptenwin=WIN_ERR;
      }
}

static void
outheader()
{
      char linebuf[BUFSZ];
      register char *bp;

      Strcpy(linebuf, " No  Points     Name");
      bp = eos(linebuf);
      while(bp < linebuf + COLNO - 9) *bp++ = ' ';
      Strcpy(bp, "Hp [max]");
      topten_print(linebuf);
}

/* so>0: standout line; so=0: ordinary line */
/* re=TRUE: report */
static void
outentry(rank, t1, so, re)
struct toptenentry *t1;
int rank;
boolean so;
boolean re;
{
      boolean second_line = TRUE;
      char linebuf[BUFSZ];
      char *bp, hpbuf[24]/*JP, linebuf3[BUFSZ]*/;
      int hppos, lngr;
/*JP*/
      char who[BUFSZ];
      char where[BUFSZ];
      char action[BUFSZ];
      char car[BUFSZ];
      char cdr[BUFSZ];
      const char *jdeath;

      linebuf[0] = '\0';
      who[0] = '\0';
      where[0] = '\0';
      action[0] = '\0';

      if (rank) Sprintf(eos(linebuf), "%3d", rank);
      else Strcat(linebuf, "   ");

/*JP  Sprintf(eos(linebuf), " %10ld  %.10s", t1->points, t1->name);*/
/*JP  Sprintf(eos(linebuf), "-%c ", t1->plchar);*/
      bp = index(pl_classes, t1->plchar);
      Sprintf(who, " %10ld  %sの", t1->points, 
            jtrns_mon(roles[bp - pl_classes], t1->sex == 'F'));
/*JP
            jtrns_mon(pl_character, flags.female));*/
      Sprintf(eos(who), "%s(%s)は", t1->name,
            t1->sex == 'F' ? "女" : "男");
/*JP*/
      jdeath = t1->death;
      if (!strncmp(jdeath, "魔除けを手に", 12))
          jdeath += 12;
      else if (!strncmp(jdeath, "天上で恥辱を受け", 16))
          jdeath += 16;
      else if (!strncmp(jdeath, "偽物の魔除けを掴まされ", 24))
          jdeath += 24;

/*JP  if (!strncmp("escaped", t1->death, 7)) {*/
      if (!strncmp("脱出した", jdeath, 8)
          || !strncmp("escaped", jdeath, 7)) {
#if 0 /*JP*/
          Sprintf(eos(linebuf), "escaped the dungeon %s[max level %d]",
                !strncmp(" (", t1->death + 7, 2) ? t1->death + 7 + 2 : "",
                t1->maxlvl);*/
          Sprintf(action, "%s迷宮から脱出した[最大地下%d階]",
                !strncmp("魔除けを手に", t1->death, 12) ?
                "魔除けを手に" : "",
                t1->maxlvl);
          /* fixup for closing paren in "escaped... with...Amulet)[max..." */
          if ((bp = index(linebuf, ')')) != 0)
            *bp = (t1->deathdnum == astral_level.dnum) ? '\0' : ' ';
#endif /*JP*/
          char jbuf[BUFSZ];
          strncpy(jbuf, t1->death, jdeath - t1->death);
          jbuf[jdeath - t1->death] = '\0';
          Sprintf(action, "%s迷宮から脱出した[最大地下%d階]",
                jbuf, t1->maxlvl);
          second_line = FALSE;
/*JP  } else if (!strncmp("ascended", t1->death, 8)) {*/
      } else if (!strncmp("昇天した", jdeath, 8)
               || !strncmp("ascended", jdeath, 8)) {
/*JP      Sprintf(eos(linebuf), "ascended to demigod%s-hood",
                (t1->sex == 'F') ? "dess" : "");*/
          Sprintf(action, "昇天し%s神となった",
                (t1->sex == 'F') ? "女" : "");
          second_line = FALSE;
      } else {
/*JP      if (!strncmp(t1->death, "quit", 4)) {*/
          if (!strncmp(jdeath, "抜けた", 4)
            || !strncmp(jdeath, "quit", 4)) {
/*JP        Strcat(linebuf, "quit");*/
            Strcat(action, t1->death);
            second_line = FALSE;
          }
#if 0
          } else if (!strncmp(t1->death, "starv", 5)) {
            Strcat(linebuf, "starved to death");
            second_line = FALSE;
          } else if (!strncmp(t1->death, "choked", 6)) {
            Sprintf(eos(linebuf), "choked on h%s food",
                  (t1->sex == 'F') ? "er" : "is");
          } else if (!strncmp(t1->death, "poisoned", 8)) {
            Strcat(linebuf, "was poisoned");
          } else if (!strncmp(t1->death, "crushed", 7)) {
            Strcat(linebuf, "was crushed to death");
          } else if (!strncmp(t1->death, "petrified by ", 13)) {
            Strcat(linebuf, "turned to stone");
          } else Strcat(linebuf, "died");
#endif /*JP*/

          if (t1->deathdnum == astral_level.dnum) {
              const char *arg/*JP, *fmt = " on the Plane of %s"*/;

            switch (t1->deathlev) {
            case -5:
/*JP
                  fmt = " on the %s Plane";
                  arg = "Astral";   break;
*/
                  arg = "命の精霊界"; break;
            case -4:
/*JP              arg = "Water";    break;*/
                  arg = "水の精霊界";     break;
            case -3:
/*JP              arg = "Fire";     break;*/
                  arg = "火の精霊界";     break;
            case -2:
/*JP              arg = "Air";      break;*/
                  arg = "風の精霊界";     break;
            case -1:
/*JP              arg = "Earth";    break;*/
                  arg = "地の精霊界";     break;
            default:
                  arg = "Void";     break;
            }
/*JP        Sprintf(eos(linebuf), fmt, arg);*/
            Sprintf(where, "%sにて", arg);
          } else {
/*JP
            Sprintf(eos(linebuf), " in %s on level %d",
                  dungeons[t1->deathdnum].dname, t1->deathlev);
*/
            Sprintf(where, "%sの地下%d階にて",
                  jtrns_obj('d', dungeons[t1->deathdnum].dname), t1->deathlev);
            if (t1->deathlev != t1->maxlvl)
/*JP            Sprintf(eos(linebuf), " [max %d]", t1->maxlvl);*/
                Sprintf(eos(where), "[最大地下%d階]", t1->maxlvl);
          }

          /* kludge for "quit while already on Charon's boat" */
          if (!strncmp(t1->death, "quit ", 5))
            Strcat(linebuf, t1->death + 4);
      }
/*JP  Strcat(linebuf, ".");*/

      /* Quit, starved, ascended, and escaped contain no second line */
      if (second_line)
/*JP      Sprintf(eos(linebuf), "  %c%s.", highc(*(t1->death)), t1->death+1);*/
          Sprintf(action, "%s", t1->death);

      Sprintf(eos(linebuf), "%s%s%s.", who, where, action);

      lngr = (int)strlen(linebuf);
      if (t1->hp <= 0) hpbuf[0] = '-', hpbuf[1] = '\0';
      else Sprintf(hpbuf, "%d", t1->hp);

      hppos = COLNO - (sizeof("  Hp [max]")-1); /* sizeof(str) includes \0 */

#ifdef NH_EXTENSION_REPORT
      if(report_flag && re){
          report_score(action, linebuf);
          send_bones();
      }
#endif
      while(lngr >= hppos ){
/*
**    hpposより前の適当な位置で分割する.
*/
        split_japanese(linebuf, car, cdr, hppos);

        bp = eos(car);
        if (so) {
          while (bp < car + (COLNO-1)) *bp++ = ' ';
          *bp = 0;
          topten_print_bold(car);
        } else
          topten_print(car);

        Sprintf(linebuf, "%15s %s", "", cdr);
        lngr = (int)strlen(linebuf);
      }

/*
**    日本語が入ると文字列を後から見ていくことはできない.
*/

#if 0 /*JP*/
      /* beginning of hp column after padding (not actually padded yet) */
      hppos = COLNO - (sizeof("  Hp [max]")-1); /* sizeof(str) includes \0 */
      while (lngr >= hppos) {
          for(bp = eos(linebuf);
                !(*bp == ' ' && (bp-linebuf < hppos));
                bp--)
            ;
          /* special case: if about to wrap in the middle of maximum
             dungeon depth reached, wrap in front of it instead */
          if (bp > linebuf + 5 && !strncmp(bp - 5, " [max", 5)) bp -= 5;
          Strcpy(linebuf3, bp+1);
          *bp = 0;
          if (so) {
            while (bp < linebuf + (COLNO-1)) *bp++ = ' ';
            *bp = 0;
            topten_print_bold(linebuf);
          } else
            topten_print(linebuf);
          Sprintf(linebuf, "%15s %s", "", linebuf3);
          lngr = strlen(linebuf);
      }
#endif /*JP*/

      /* beginning of hp column not including padding */
      hppos = COLNO - 7 - (int)strlen(hpbuf);
      bp = eos(linebuf);

      if (bp <= linebuf + hppos) {
          /* pad any necessary blanks to the hit point entry */
          while (bp < linebuf + hppos) *bp++ = ' ';
          Strcpy(bp, hpbuf);
          Sprintf(eos(bp), " %s[%d]",
                (t1->maxhp < 10) ? "  " : (t1->maxhp < 100) ? " " : "",
                t1->maxhp);
      }

      if (so) {
          bp = eos(linebuf);
          if (so >= COLNO) so = COLNO-1;
          while (bp < linebuf + so) *bp++ = ' ';
          *bp = 0;
          topten_print_bold(linebuf);
      } else
          topten_print(linebuf);

}
static int
score_wanted(current_ver, rank, t1, playerct, players, uid)
boolean current_ver;
int rank;
struct toptenentry *t1;
int playerct;
const char **players;
int uid;
{
      int i;

      if (current_ver && (t1->ver_major != VERSION_MAJOR ||
                      t1->ver_minor != VERSION_MINOR ||
                      t1->patchlevel != PATCHLEVEL))
            return 0;

#ifdef PERS_IS_UID
      if (!playerct && t1->uid == uid)
            return 1;
#endif

      for (i = 0; i < playerct; i++) {
            if (strcmp(players[i], "all") == 0 ||
                strncmp(t1->name, players[i], NAMSZ) == 0 ||
                (players[i][0] == '-' &&
                 players[i][1] == t1->plchar &&
                 players[i][2] == 0) ||
                (digit(players[i][0]) && rank <= atoi(players[i])))
            return 1;
      }
      return 0;
}

/*
 * print selected parts of score list.
 * argc >= 2, with argv[0] untrustworthy (directory names, et al.),
 * and argv[1] starting with "-s".
 */
void
prscore(argc,argv)
int argc;
char **argv;
{
      const char **players;
      int playerct, rank;
      boolean current_ver = TRUE, init_done = FALSE;
      register struct toptenentry *t1;
      FILE *rfile;
      boolean match_found = FALSE;
      register int i;
      char pbuf[BUFSZ];
      int uid = -1;
#ifndef PERS_IS_UID
      const char *player0;
#endif

      if (argc < 2 || strncmp(argv[1], "-s", 2)) {
            raw_printf("prscore: bad arguments (%d)", argc);
            return;
      }

      rfile = fopen_datafile(RECORD, "r");
      if (!rfile) {
            raw_print("Cannot open record file!");
            return;
      }

#ifdef      AMIGA
      {
          extern winid amii_rawprwin;
          init_nhwindows(&argc, argv);
          amii_rawprwin = create_nhwindow(NHW_TEXT);
      }
#endif

      /* If the score list isn't after a game, we never went through
       * initialization. */
      if (wiz1_level.dlevel == 0) {
            dlb_init();
            init_dungeons();
            init_done = TRUE;
      }

      if (!argv[1][2]){ /* plain "-s" */
            argc--;
            argv++;
      } else if (!argv[1][3] && index(pl_classes, argv[1][2])) {
            /* may get this case instead of next accidentally,
             * but neither is listed in the documentation, so
             * anything useful that happens is a bonus anyway */
            argv[1]++;
            argv[1][0] = '-';
      } else      argv[1] += 2;

      if (argc > 1 && !strcmp(argv[1], "-v")) {
            current_ver = FALSE;
            argc--;
            argv++;
      }

      if (argc <= 1) {
#ifdef PERS_IS_UID
            uid = getuid();
            playerct = 0;
            players = (const char **)0;
#else
            player0 = plname;
            if (!*player0)
# ifdef AMIGA
                  player0 = "all";  /* single user system */
# else
                  player0 = "hackplayer";
# endif
            playerct = 1;
            players = &player0;
#endif
      } else {
            playerct = --argc;
            players = (const char **)++argv;
      }
      raw_print("");

      t1 = tt_head = newttentry();
      for (rank = 1; ; rank++) {
          readentry(rfile, t1);
          if (t1->points == 0) break;
          if (!match_found &&
                score_wanted(current_ver, rank, t1, playerct, players, uid))
            match_found = TRUE;
          t1->tt_next = newttentry();
          t1 = t1->tt_next;
      }

      (void) fclose(rfile);
      if (init_done) {
          free_dungeons();
          dlb_cleanup();
      }

      if (match_found) {
          outheader();
          t1 = tt_head;
          for (rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
            if (score_wanted(current_ver, rank, t1, playerct, players, uid))
                (void) outentry(rank, t1, 0, 0);
          }
      } else {
          Sprintf(pbuf, "Cannot find any %sentries for ",
                        current_ver ? "current " : "");
          if (playerct < 1) Strcat(pbuf, "you.");
          else {
            if (playerct > 1) Strcat(pbuf, "any of ");
            for (i = 0; i < playerct; i++) {
                Strcat(pbuf, players[i]);
                if (i < playerct-1) Strcat(pbuf, ":");
            }
          }
          raw_print(pbuf);
          raw_printf("Call is: %s -s [-v] [-role] [maxrank] [playernames]",
                   hname);
      }
      free_ttlist(tt_head);
#ifdef      AMIGA
      display_nhwindow(amii_rawprwin, 1);
      destroy_nhwindow(amii_rawprwin);
      amii_rawprwin = WIN_ERR;
#endif
}

static int
classmon(plch, fem)
char plch;
boolean fem;
{
      switch (plch) {
            case 'A': return PM_ARCHEOLOGIST;
            case 'B': return PM_BARBARIAN;
            case 'C': return (fem ? PM_CAVEWOMAN : PM_CAVEMAN);
            case 'E': return PM_ELF;
            case 'H': return PM_HEALER;
#ifndef FIGHTER
            case 'F':   /* accept old Fighter class */
#else
            case 'F': return PM_FIGHTER;
#endif
            case 'K': return PM_KNIGHT;
            case 'P': return (fem ? PM_PRIESTESS : PM_PRIEST);
            case 'R': return PM_ROGUE;
            case 'N':   /* accept old Ninja class */
            case 'S': return PM_SAMURAI;
#ifdef TOURIST
            case 'T': return PM_TOURIST;
#else
            case 'T': return PM_HUMAN;
#endif
            case 'V': return PM_VALKYRIE;
            case 'W': return PM_WIZARD;
            default: impossible("What weird class is this? (%c)", plch);
                  return PM_HUMAN_ZOMBIE;
      }
}

/*
 * Get a random player name and class from the high score list,
 * and attach them to an object (for statues or morgue corpses).
 */
struct obj *
tt_oname(otmp)
struct obj *otmp;
{
      int rank;
      register int i;
      register struct toptenentry *tt;
      FILE *rfile;
      struct toptenentry tt_buf;

      if (!otmp) return((struct obj *) 0);

      rfile = fopen_datafile(RECORD, "r");
      if (!rfile) {
            impossible("Cannot open record file!");
            return (struct obj *)0;
      }

      tt = &tt_buf;
      rank = rnd(10);
pickentry:
      for(i = rank; i; i--) {
          readentry(rfile, tt);
          if(tt->points == 0) break;
      }

      if(tt->points == 0) {
            if(rank > 1) {
                  rank = 1;
                  rewind(rfile);
                  goto pickentry;
            }
            otmp = (struct obj *) 0;
      } else {
            /* reset timer in case corpse started out as lizard or troll */
            if (otmp->otyp == CORPSE) obj_stop_timers(otmp);
            otmp->corpsenm = classmon(tt->plchar, (tt->sex == 'F'));
            otmp->owt = weight(otmp);
            otmp = oname(otmp, tt->name);
            if (otmp->otyp == CORPSE) start_corpse_timeout(otmp);
      }

      (void) fclose(rfile);
      return otmp;
}

#ifdef NO_SCAN_BRACK
/* Lattice scanf isn't up to reading the scorefile.  What */
/* follows deals with that; I admit it's ugly. (KL) */
/* Now generally available (KL) */
static void
nsb_mung_line(p)
      char *p;
{
      while ((p = index(p, ' ')) != 0) *p = '|';
}

static void
nsb_unmung_line(p)
      char *p;
{
      while ((p = index(p, '|')) != 0) *p = ' ';
}
#endif /* NO_SCAN_BRACK */

#ifdef GTK_GRAPHICS
winid
create_toptenwin()
{
    toptenwin = create_nhwindow(NHW_TEXT);

    return toptenwin;
}
#endif
/*topten.c*/

Generated by  Doxygen 1.6.0   Back to index