回精華區
作者itoc (核心動力), 信區: itoc
標題Re: 請問rpg冒險者的排行榜應該怎麼做呢???
時間2004/10/25 Mon 23:55:04 Updated: 2004/10/26
※ 引述《comfan (難過  傷心)》之銘言:
> wd的rpg角色扮演遊戲裡面有一個子選單 [L]istTop    使用者排行榜
> 進入該選單之後   看到的是下列的畫面   不知道在Maple裡面是否也有辦法做出
> 像站上rpg使用者的排行榜類似的功能

  在本例中只排行 maxhp 及 str 欄位
  想知道有哪些欄位,請參考 rpg.h

  在 (A)nnounce 裡面新增資料,路徑為 -rpgmaxhp 及 -rpgstr

: crontab -e 加入這二行

# 每天作二次 RPG 排行
35 3,15 * * * * bin/toprpg > /dev/null 2>&1

: src/util/Makefile

EXE =   ... toprpg

: src/util/toprpg.c 新增此程式

/*-------------------------------------------------------*/
/* util/toprpg.c        ( NTHU CS MapleBBS Ver 3.00 )    */
/*-------------------------------------------------------*/
/* target : 使用者 RPG 資料統計及排名                    */
/* create : 04/10/25                                     */
/* update :   /  /                                       */
/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw                 */
/*-------------------------------------------------------*/


#include "bbs.h"


// 還要統計別的欄位的話,這裡加一行檔案路徑 
// 並在 (A)nnounce 新增「資料」指向這些檔案 
#define OUTFILE_RPGMAXHP BBSHOME"/gem/@/@-rpgmaxhp"
#define OUTFILE_RPGSTR   BBSHOME"/gem/@/@-rpgstr"


/*-------------------------------------------------------*/
/* author : mat.bbs@fall.twbbs.org                       */
/* modify : gslin@abpe.org                               */
/*-------------------------------------------------------*/


#define TOPNUM          (36)
#define TOPNUM_HALF     (TOPNUM/2)


typedef struct
{
  char userid[IDLEN + 1];
  char username[UNLEN + 1];
  int num;
}      DATA;

// 還要統計別的欄位的話,這裡加一個宣告 
static DATA topmaxhp[TOPNUM];
static DATA topstr[TOPNUM];


static int
sort_compare(p1, p2)
  const void *p1;
  const void *p2;
{
  DATA *a1, *a2;

  a1 = (DATA *) p1;
  a2 = (DATA *) p2;

  return (a2->num - a1->num);
}


static DATA *
findmin(src)
  DATA *src;
{
  int i;
  DATA *p;

  p = src;
  for (i = 0; i < TOPNUM; i++)
  {
    if (src[i].num < p->num)
      p = src + i;
  }
  return p;
}


static void
merge_id_nick(dst, userid, nick)
  char *dst;
  char *userid;
  char *nick;
{
  if (*userid)
  {
    sprintf(dst, "%s (%s)", userid, nick);

    if (strlen(dst) > 25)
      dst[25] = 0;
  }
  else
    dst[0] = 0;
}


static void
write_data(fpath, title, data)
  char *fpath;
  char *title;
  DATA *data;
{
  FILE *fp;
  char buf[256];
  int i, num1, num2;

  if (!(fp = fopen(fpath, "w")))
    return;

  i = 12 - (strlen(title) >> 1);
  sprintf(buf, " \033[1;33m○ ──────────→ \033[41m%%%ds%%s%%%ds"
    "\033[40m ←────────── ○\033[m\n\n", i, i);
  fprintf(fp, buf, "", title, "");

  fprintf(fp,
    "\033[1;37m名次  \033[33m代號(暱稱)                \033[36m數量\033[m   "
    "\033[1;37m名次  \033[33m代號(暱稱)                \033[36m數量\033[m\n"
    "\033[1;32m%s\033[m\n", MSG_SEPERATOR);

  for (i = 0; i < TOPNUM_HALF; i++)
  {
    char buf1[80], buf2[80];

    merge_id_nick(buf1, data[i].userid, data[i].username);
    merge_id_nick(buf2, data[i + TOPNUM_HALF].userid,
      data[i + TOPNUM_HALF].username);

    /* itoc.010408: 解決錢太多,畫面爆掉的問題 */
    num1 = data[i].num / 1000000;
    num2 = data[i + TOPNUM_HALF].num / 1000000;
    if (num2)                   /* 那麼 data[i].num 也必定 > 10^6 */
    {
      fprintf(fp, "[%2d] %-25s %5dM  [%2d] %-25s %5dM\n", i + 1, buf1, num1,
        i + 1 + TOPNUM_HALF, buf2, num2);
    }
    else if (num1)
    {
      fprintf(fp, "[%2d] %-25s %5dM  [%2d] %-25s %6d\n", i + 1, buf1, num1,
        i + 1 + TOPNUM_HALF, buf2, data[i + TOPNUM_HALF].num);
    }
    else
    {
      fprintf(fp, "[%2d] %-25s %6d  [%2d] %-25s %6d\n",
        i + 1, buf1, data[i].num,
        i + 1 + TOPNUM_HALF, buf2, data[i + TOPNUM_HALF].num);
    }
  }

  fprintf(fp, "\n");
  fclose(fp);
}


static inline void
topusr(acct)
  ACCT *acct;
{
  DATA *p;
  int fd;
  char fpath[64];
  RPG rpg;

  sprintf(fpath, "%s/"FN_RPG, acct->userid);
  if ((fd = open(fpath, O_RDONLY)) < 0)
    return;
  read(fd, &rpg, sizeof(RPG));
  close(fd);

  // 還要統計別的欄位的話,這裡加一個 if (...) {...} 共六行 

  if ((p = findmin(&topmaxhp))->num < rpg.maxhp)
  {
    str_ncpy(p->userid, acct->userid, sizeof(p->userid));
    str_ncpy(p->username, acct->username, sizeof(p->username));
    p->num = rpg.maxhp;
  }

  if ((p = findmin(&topstr))->num < rpg.str)
  {
    str_ncpy(p->userid, acct->userid, sizeof(p->userid));
    str_ncpy(p->username, acct->username, sizeof(p->username));
    p->num = rpg.str;
  }
}


/*-------------------------------------------------------*/
/* 主程式                                                */
/*-------------------------------------------------------*/


int
main()
{
  char c;
  int year, month, day;
  time_t now;
  struct tm *ptime;

  // 還要統計別的欄位的話,這裡加一行 
  memset(&topmaxhp, 0, sizeof(topmaxhp));
  memset(&topstr, 0, sizeof(topstr));

  now = time(NULL);
  ptime = localtime(&now);

  year = ptime->tm_year;
  month = ptime->tm_mon + 1;
  day = ptime->tm_mday;

  for (c = 'a'; c <= 'z'; c++)
  {
    char buf[64];
    struct dirent *de;
    DIR *dirp;

    sprintf(buf, BBSHOME "/usr/%c", c);
    chdir(buf);

    if (!(dirp = opendir(".")))
      continue;

    while (de = readdir(dirp))
    {
      ACCT acct;
      int fd;
      char *fname;

      fname = de->d_name;
      if (*fname <= ' ' || *fname == '.')
        continue;

      sprintf(buf, "%s/.ACCT", fname);
      if ((fd = open(buf, O_RDONLY)) < 0)
        continue;

      read(fd, &acct, sizeof(ACCT));
      close(fd);

      topusr(&acct);
    }

    closedir(dirp);
  }

  // 還要統計別的欄位的話,這裡加二行 

  qsort(topmaxhp, TOPNUM, sizeof(DATA), sort_compare);
  write_data(OUTFILE_RPGMAXHP, "RPG血牛排行榜", &topmaxhp);

  qsort(topstr, TOPNUM, sizeof(DATA), sort_compare);
  write_data(OUTFILE_RPGSTR, "RPG力士排行榜", &topstr);

  return 0;
}


--
  Origin:  Maple-itoc˙動力核心  processor.tfcis.org 
  Author: itoc itoc.Dorm11.NCTU.edu.tw 發表
精華選讀←離開[主題上]主題下(k)上篇(j)下篇S/a搜尋 G串列 TAB精華 ↑↓捲 Pg/Space翻