回文章列表
作者waynesan.bbs@csc241.twbbs.org (ln -s /dev/null hea 看板: itoc
標題[更新] bet.c 賭盤主程式仿 xover 介面
時間迷幻國度 (2008/03/21 Fri 01:34:37)
這陣子很多站都在玩押大選,

但是還在用舊版code的站沒有內建投票可兼賭盤的功能,

因此就照精華區加了bet.c系列的code下去.....

或許是這code已經有一段時間沒人更新了...所以介面感覺有點陽春......

這兩天花了時間將整個bet.c幾乎重寫,做成仿xover的介面.....

而資料結構方面都沒做改變與原本的相容........

如果有其他站之前也有加這個功能的話可以更新一下這個新介面....^^"

-----------------------------------------------------------------------------

: ~bbs/src/game/bet.c

/*-------------------------------------------------------*/
/* game/bet.c     ( NTHU CS MapleBBS Ver 3.00 )          */
/*-------------------------------------------------------*/
/* target : 瘋狂賭盤 (原名:下注遊戲)                     */
/* create : 04/08/23                                     */
/* update : 08/03/20                                     */
/* author : dsyan.bbs@Forever.twbbs.org                  */
/* modify : weiren@weiren.net                            */
/* modify : waynesan.bbs@csc241.twbbs.org                */
/*-------------------------------------------------------*/

#if 0
   原構想及程式由 dsyan 提供及撰寫..
   後經 weiren 改寫部分架構得雛型程式..
   再經 waynesan 改寫整體架構而成本程式..
   有任何問題或建議歡迎與這三位連絡.. :)
   dsyan 是天長地久(Forever.twbbs.org) 的站長
   =>dsyan.bbs@Forever.twbbs.org
   weiren 是荒謬化境 (weird.twbbs.org.tw) 的站長
   =>weiren@weiren.net
   waynesan 是迷幻國度 (csc241.twbbs.org) 的站長
   =>waynesan.bbs@csc241.twbbs.org
#endif

#include "bbs.h"

#define MAX_BET     40
#define NEW_GAME    5           /* 最後開的幾局要變色 */
#define LOCK_FILE   "etc/game/bet/bet.lock"

#define NECKER_BET  "[←]離開 [↑↓]選擇 [→,b]下注/開局/開盤 [h]說明 \n" \
            COLOR3 "編號  單  價  項    目    敘    述%*s                     [ 開 局 者 ] [剩餘時間]\033[m"
#define FEETER_BET \
            COLOR1 " 賭盤列表 " COLOR2 " (↑/↓)上下 (PgUp/PgDn)上下頁 (Home/End)首尾 (←)(q)離開         "

static void
add_post(brdname, fpath, title) /* 發文到看板 */
  char *brdname;                /* 欲 post 的看板 */
  char *fpath;                  /* 檔案路徑 */
  char *title;                  /* 文章標題 */
{
  HDR hdr;
  char folder[64];

  brd_fpath(folder, brdname, FN_DIR);
  hdr_stamp(folder, HDR_LINK | 'A', &hdr, fpath);
  strcpy(hdr.owner, STR_SYSOP);
  strcpy(hdr.nick, SYSOPNICK);
  strcpy(hdr.title, title);
  hdr.xmode = POST_MARKED;
  rec_bot(folder, &hdr, sizeof(HDR));

  btime_update(brd_bno(brdname));
}

typedef struct
{
    int money;
    time_t close_time;
    char userid[IDLEN + 1];
    char title[TTLEN + 1];
}   BET;

static int
open_bet(num, bet)      /* 自己來開局 */
  int num;
  BET *bet;
{
  int i, khour, kd, chn, newbet[NEW_GAME];
  char buf[60], fpath[64], cho[9][51];
  FILE *fs, *fss;

  more("etc/game/bet/bet.anno", NULL);
  if (vans("確定要開局(Y/N)?[N] ") != 'y')
    return 0;

  if (dashf(LOCK_FILE))
  {
    vmsg("發錢時間停止下注");
    return -1;
  }

  vmsg("請按任一鍵開始編輯此次 [開局宗旨]");
  sprintf(fpath, "tmp/%s_bet.scr", cuser.userid);
  if (vedit(fpath, 0) < 0)
    return 0;

//    move(1,0);
//    clrtobot();
  vs_bar("瘋狂賭盤");
  vget(2, 0, "請填停注時間幾小時後(十位數要補0,0請輸入00,1請輸入01,以此類推):", buf, 3, DOECHO);
  khour = (buf[0] - '0') * 10 + (buf[1] - '0');
  vget(3, 0, "請填停注時間天後(十位數要補0,0請輸入00,1請輸入01,以此類推):", buf, 3, DOECHO);
  kd = (buf[0] - '0') * 10 + (buf[1] - '0');
  if (khour < 10 && kd == 0)
  {
    vmsg("時間過短(最短 10 小時)");
    return 0;
  }
  if (kd > 14)
  {
    vmsg("時間過長(最長 14 天)");
    return 0;
  }
  if (khour > 24)
  {
    vmsg("時間不可超過24小時");
    return 0;
  }
  if (kd < 0 || khour < 0)
  {
    vmsg("十位數記得補0");
    return 0;
  }
  bet->close_time = time(0) + khour * 3600 + kd * 24 * 3600;

  if (!vget(4, 0, "請簡短敘述此局:", bet->title, 41, DOECHO))
    return 0;

  move(5, 0);
  outs("\033[1;31m設定選項,請注意和局、比賽取消等狀況,絕不可沒有答案,設定後不可更改。\033[m");

  vget(6, 0, "共有幾個選項?(2~9)", buf, 2, DOECHO);
  chn = buf[0] - '0';
  if (chn < 2 || chn > 9)
  {
    vmsg("選項數目錯誤!!");
    return 0;
  }

  vget(7, 0, "彩券一張多少錢?(100~10000)", buf, 6, DOECHO);
  bet->money = atoi(buf);
  if (bet->money < 100 || bet->money > 10000)
  {
    vmsg("輸入金額錯誤!!");
    return 0;
  }
  if (cuser.money < bet->money * (10 * chn + 5))
  {
    sprintf(buf, "你的錢不足 %d 元喔!!", bet->money * (10 * chn + 5));
    vmsg(buf);
    return 0;
  }
  for (i = 0; i < chn; ++i)
  {
    move(8 + i, 0);
    prints("選項%d:", i + 1);
    do
    {
      vget(8 + i, 7, "", cho[i], 50, DOECHO);
    } while (!cho[i][0]);
  }

  if (dashf(LOCK_FILE))
  {
    vmsg("發錢時間停止下注");
    return -1;
  }

  sprintf(fpath, "etc/game/bet/bet.cho%d", num);
  if (dashf(fpath))
  {
    fclose(fs);
    vmsg("有人比你快一步了");
    return 1;
  }

  if (vans("確定開局(Y/N)?[N] ") != 'y')
  {
    sprintf(fpath, "etc/game/bet/bet.scr%d", num);
    unlink(fpath);
    sprintf(fpath, "tmp/%s_bet.*", cuser.userid);
    unlink(fpath);
    vmsg("開局取消!");
    return 0;
  }

  fs = fopen(fpath, "w");
  fprintf(fs, "%d\n%d\n", chn, chn * 10);
  for (i = 0; i < chn; ++i)
  {
    fprintf(fs, "%s\n10\n", cho[i]);
    sprintf(fpath, "etc/game/bet/bet.cho%d.%d", num, i + 1);
    fss = fopen(fpath, "a+");
    fprintf(fss, "%s %d\n", cuser.userid, 10);
    fclose(fss);
  }
  fclose(fs);

  if (fss = fopen("etc/game/bet/bet.new", "r"))
  {
    for (i = 0; i < NEW_GAME; ++i)
      fscanf(fss, "%d\n", &newbet[i]);
    fclose(fss);
  }

  if (fss = fopen("etc/game/bet/bet.new", "w"))
  {
    fprintf(fss, "%d\n", num);
    for (i = 0; i < NEW_GAME - 1; ++i)
      fprintf(fss, "%d\n", newbet[i]);
    fclose(fss);
  }

  cuser.money -= (bet->money * (10 * chn + 5));

  fs = fopen("etc/game/bet/bet.list", "r");
  fss = fopen("etc/game/bet/bet.list.w", "w");
  for (i = 0; i < MAXBOARD; ++i)
  {
    if (i + 1 == num)
    {
      fgets(buf, 60, fs);   /* 借用 fpath */
      fgets(buf, 60, fs);   /* 借用 fpath */
      fprintf(fss, "%d %ld %s\n", bet->money, bet->close_time, cuser.userid);
      fprintf(fss, "%s\n", bet->title);
    }
    else
    {
      fgets(buf, 60, fs);
      fprintf(fss, buf);
      fgets(buf, 60, fs);
      fprintf(fss, buf);
    }
  }
  fclose(fs);
  fclose(fss);
  f_mv("etc/game/bet/bet.list.w", "etc/game/bet/bet.list");

  sprintf(buf, "tmp/%s_bet.scr", cuser.userid);
  sprintf(fpath, "etc/game/bet/bet.scr%d", num);
  f_mv(buf, fpath);
  sprintf(fpath, "tmp/%s_bet.*", cuser.userid);
  unlink(fpath);

  vmsg("開局完成!");
  return 1;
}

static int
end_bet(num, bet)       /* 公佈開盤結果 */
  int num;
  BET *bet;
{
  char fpath[64];

  sprintf(fpath, "etc/game/bet/bet.ans%d", num);
  if (dashf(fpath))
  {
    vmsg("結果已公佈,獎金將於明天 6:30am 發放...:)");
    return 0;
  }

  if (strcmp(bet->userid, cuser.userid))
  {
    sprintf(fpath, "下注期限已到,等待 %s 開盤...", bet->userid);   /* 借用 fpath */
    vmsg(fpath);
    return 0;
  }

  while(1)
  {
    int i, ch[9], ans, chn, all = 0;
    char cc[10], cho[9][51];
    FILE *fs;

    vmsg("下注期限已到,請輸入開盤的結果!");

    move(1,0);
    clrtobot();
    vs_bar("瘋狂賭盤");
    prints("\n\n\033[44;1m  賭券數    倍率      敘  述           \033[m\n\n");
    sprintf(fpath, "etc/game/bet/bet.cho%d", num);
    fs = fopen(fpath, "r");
    fscanf(fs, "%d\n%d\n", &chn, &all);
    for (i = 0; i < chn; ++i)
    {
      long xx;
      fgets(cho[i], 60, fs);
      fscanf(fs, "%d\n", &ch[i]);
      xx = all * 100 / ch[i];
      prints("%d)%6d   %3d.%-2d   %s", i + 1, ch[i], xx / 100, xx % 100, cho[i]);
    }
    fclose(fs);

    vmsg("注意:亂開盤者,將處以停權與金錢歸零的處分!");

    move(b_lines - 1, 0);
    prints("\033[1;31m注意:亂開盤者,將處以停權與金錢歸零的處分!\033[m");
    sprintf(fpath, "請輸入最後的結果(1~%d)或按 q 離開:", chn); /* 借用 fpath */

    vget(b_lines, 0, fpath, cc, 2, DOECHO);

    if (cc[0] == 'q')
      return 0;

    if (dashf(LOCK_FILE))
    {
      vmsg("發錢時間停止下注");
      return -1;
    }

    ans = cc[0] - '0';
    if (ans < 1 || ans > chn )
    {
      vmsg("輸入範圍有誤!!請重新輸入..");
      continue;
    }

    if (vans(msg_sure_ny) == 'y')
    {
      char title[TTLEN + 1], fname[64];

      if (dashf(LOCK_FILE))
      {
        vmsg("發錢時間停止下注");
        return -1;
      }

      sprintf(fpath, "etc/game/bet/bet.ans%d", num);
      fs = fopen(fpath, "w");
      fprintf(fs, "%d", ans);
      fclose(fs);

      sprintf(fpath, "tmp/addpost.tmp%d", num);
      if (fs = fopen(fpath, "w"))
      {
        sprintf(title, "[公告] 瘋狂賭盤 盤號[%d] 封盤結果", num);
        fprintf(fs, "%s %s (%s) %s %s\n", STR_AUTHOR1, STR_SYSOP, SYSOPNICK, STR_POST2, BN_BET);
        fprintf(fs, "標題: %s\n時間: %s\n\n", title, Now());

        fprintf(fs, "\n[開盤結果]:\033[1;3%dm%d號\033[m\n", ans % 8, ans);
        fprintf(fs, "\n[開 盤 者]:\033[1m%s\033[m\n", cuser.userid);
        fprintf(fs, "\n[開局宗旨]\n\n");
        sprintf(fname, "etc/game/bet/bet.scr%d", num);
        f_suck(fs, fname);
        fprintf(fs, "\n[開局選項]\n\n");
        sprintf(fname, "etc/game/bet/bet.cho%d", num);
        f_suck(fs, fname);
        fprintf(fs, "\n--\n※ 以下為此次下注狀況,明天早上6:30將發放獎金\n\n");
        sprintf(fname, "etc/game/bet/bet.betlog%d", num);
        f_suck(fs, fname);
        fclose(fs);

        add_post(BN_BET, fpath, title);
        unlink(fpath);
        unlink(fname);
      }

      return 1;
    }
  }
}

static int
buy_bet(num, bet)       /* 下注買賭券 */
  int num;
  BET *bet;
{
  char buf[100], fpath[64];

  sprintf(fpath, "etc/game/bet/bet.scr%d", num);
  more(fpath, NULL);
  while (1)
  {
    int i, ch[9], ans, chn, all = 0, pall = 0;
    char cc[10], cho[9][51];
    FILE *fs, *fss;

//    move(1,0);
//    clrtobot();
    vs_bar("瘋狂賭盤");
    prints("\n\n\033[44;1m  賭券數       倍率      敘  述           \033[m\n\n");
    sprintf(fpath, "etc/game/bet/bet.cho%d", num);
    fs = fopen(fpath, "r");
    fscanf(fs, "%d\n%d\n", &chn, &all);
    for (i = 0; i < chn; ++i)
    {
      int phh = 0;
      long xx;  /* 倍率 */

      fgets(cho[i], 60, fs);        /* 取描述 */
      fscanf(fs, "%d\n", &ch[i]);   /* 取票數 */

      sprintf(fpath, "etc/game/bet/bet.cho%d.%d", num, i + 1);
      if (fss = fopen(fpath, "r"))
      {
        int hh = 0;
        char id[IDLEN + 1];
        while (fscanf(fss, "%s %d\n", id, &hh) != EOF)
        {
          if (!strcmp(id, cuser.userid))
          {
            phh += hh;
            pall += hh;
          }
        }
        fclose(fss);
      }

      xx = all * 100 / ch[i];
      prints("%2d)%4d/%4d   %3d.%-2d   %s", i + 1, phh, ch[i], xx / 100, xx % 100, cho[i]);
    }
    fclose(fs);
    prints("\n全>%4d/%4d\n", pall, all);
    prints("\n本局總賭金: \033[1;36m%d\033[m 單張賭券價格: \033[1m%d\033[m", all * bet->money, bet->money);

    sprintf(buf, "請輸入你的選擇(1~%d)或按 q 跳出:", chn);
    vget(b_lines, 0, buf, cc, 2, DOECHO);
    if (cc[0] == 'q')
      return 0;

    if (dashf(LOCK_FILE))
    {
      vmsg("發錢時間停止下注");
      return -1;
    }

    ans = cc[0] - '0';
    if (ans < 1 || ans > chn )
    {
      vmsg("輸入範圍有誤!!請重新輸入..");
      continue;
    }

    sprintf(buf, "一張賭券銀幣%d元,你目前有銀幣%d元,要買幾張?(0-%d)",
      bet->money, cuser.money, cuser.money / bet->money);
    vget(b_lines, 0, buf, cc, 6, DOECHO);

    if (atoi(cc) > cuser.money / bet->money || !atoi(cc) ||(atoi(cc) < 1))
    {
      vmsg("輸入範圍有誤!!取消..");
      continue;
    }

    if (vans(msg_sure_ny) != 'y')
      continue;

    if (dashf(LOCK_FILE))
    {
      vmsg("發錢時間停止下注");
      return -1;
    }

    if (bet->close_time < time(0))
    {
      vmsg("超過時間了!");
      return 1;
    }

    sprintf(fpath, "etc/game/bet/bet.cho%d", num);
    fs = fopen(fpath, "r");
    fscanf(fs, "%d\n%d\n", &chn, &all);
    for (i = 0; i < chn; ++i)
    {
      fgets(cho[i], 250, fs);
      fscanf(fs, "%d\n", &ch[i]);
    }
    fclose(fs);

    cuser.money -= (atoi(cc) * bet->money);

    ch[ans - 1] += atoi(cc);
    all += atoi(cc);
    fs = fopen(fpath, "w");
    fprintf(fs, "%d\n%d\n", chn, all);
    for (i = 0; i < chn; ++i)
    {
      char g = strlen(cho[i]) - 1;
      cho[i][g] = 0;
      fprintf(fs, "%s\n%d\n", cho[i], ch[i]);
    }
    fclose(fs);

    sprintf(fpath, "etc/game/bet/bet.cho%d.%d", num, ans);
    fs = fopen(fpath, "a");
    fprintf(fs, "%s %d\n", cuser.userid, atoi(cc));
    fclose(fs);

    sprintf(fpath, "etc/game/bet/bet.betlog%d", num);
    sprintf(buf, "使用者 \033[1m%s\033[m 買了 \033[1m%d張\033[m 的 \033[1;3%dm%d號\033[m 賭券 (%s)\n",
      cuser.userid, atoi(cc), ans % 8, ans, Now());
    f_cat(fpath, buf);

    vmsg("購買完成!");
  }
}

static int          /* 0:redraw 1:reload -1:return */
do_bet(num, bet)
  int num;
  BET *bet;
{
  if (dashf(LOCK_FILE))
  {
    vmsg("發錢時間停止下注");
    return -1;
  }

  if (bet->money > 0)               /* 已有人開局 */
    if (bet->close_time < time(0))  /* 下注時間到 */
      return end_bet(num, bet);     /* 公佈開盤結果 */
    else
      return buy_bet(num, bet);     /* 下注買賭券 */
  else                              /* 自己來開局 */
    return open_bet(num, bet);
}

static void
show_bet(num, bet, newbet)
  int num;
  BET *bet;
  int *newbet;
{

  if (bet->money > 0)               /* 已有人開局 */
  {
    int i, color;
    char buf[60];

    for (i = 0; i < NEW_GAME; ++i)
    {
      if (newbet[i] == num)
      {
        color = 1;
        break;
      }
      color = 0;
    }

    sprintf(buf, "etc/game/bet/bet.ans%d", num);
    if (fopen(buf, "r"))    /* bet.ans 檔案存在 */
    {
      prints(" \033[35;1m %2d   %5d  %-*.*s %-12s [等待發錢]\033[m\n",
        num, bet->money, d_cols + 40, d_cols + 40, bet->title, bet->userid);
    }
    else if (bet->close_time - time(0) > 0) /* 時間未到 */
    {
      int day = (bet->close_time - time(0)) / 3600 / 24;
      int hour = (bet->close_time - time(0)) / 3600 % 24;
      prints(" \033[%d;37m %2d   %5d  %-*.*s %-12s \033[1;%dm%2d天%2d小時\033[m\n",
        color, num, bet->money, d_cols + 40, d_cols + 40,
        bet->title, bet->userid, day < 1 ? (hour < 10 ? 31 : 33) : 37, day, hour);
    }
    else
      prints(" \033[32;1m %2d   %5d  %-*.*s %-12s [ 封  盤 ]\033[m\n",
        num, bet->money, d_cols + 40, d_cols + 40, bet->title, bet->userid);
  }
  else
    prints(" \033[1;30m %2d   -----  ======== 尚未有人開局 ========  \033[m\n", num);
}

int
main_bet()  /* waynesan.080317:賭盤主程式,仿 xover 的介面 */
{
  int pageno, pagemax, redraw, reload;
  int ch, cur, pos, newbet[NEW_GAME];
  BET bet[MAX_BET];

  if (HAS_STATUS(STATUS_COINLOCK))
  {
    vmsg(msg_coinlock);
    return XEASY;
  }

  more("etc/game/bet/bet.welcome", NULL);

  if (dashf(LOCK_FILE))
  {
    vmsg("發錢時間停止下注");
    return -1;
  }

  reload = 1;
  pageno = 0;
  cur = 0;

  do
  {
    if (reload)
    {
      int i;
      FILE *fs;

      if (fs = fopen("etc/game/bet/bet.new", "r"))
      {
        for (i = 0; i < NEW_GAME; ++i)
          fscanf(fs, "%d\n", &newbet[i]);
        fclose(fs);
      }

      fs = fopen("etc/game/bet/bet.list", "r");
      for (i = 0; i < MAX_BET; ++i)
      {
        fscanf(fs, "%d %ld %s\n", &bet[i].money, &bet[i].close_time, bet[i].userid);
        fgets(bet[i].title, TTLEN - 1, fs);
        ch = strlen(bet[i].title) - 1;  /* 借用 ch */
        bet[i].title[ch] = 0;
      }
      fclose(fs);

      pagemax = (MAX_BET - 1) / XO_TALL;
      reload = 0;
      redraw = 1;
    }

    if (redraw)
    {
      char buf[60];
      sprintf(buf, "《 擁有銀幣:%d 》", cuser.money);
      vs_head("瘋狂賭盤", buf);
      prints(NECKER_BET "\n", d_cols, "");

      pos = pageno * XO_TALL;
      ch = BMIN(MAX_BET - 1, pos + b_lines - 4);
      move(3, 0);
      do
      {
        show_bet(pos + 1, &bet[pos], newbet);
      } while (++pos <= ch);

      outf(FEETER_BET);
      move(3 + cur, 0);
      outc('>');
      redraw = 0;
    }

    ch = vkey();
    switch (ch)
    {
    case KEY_RIGHT:
    case '\n':
    case 'b':
      pos = cur + pageno * XO_TALL;
      if ((reload = do_bet(pos + 1, &bet[pos])) == -1)
        return 0;
      redraw = 1;
      break;
    case 'h':
      more("etc/game/bet/bet.welcome", NULL);
      redraw = 1;
      break;
    default:
      ch = xo_cursor(ch, pagemax, MAX_BET - 1, &pageno, &cur, &redraw);
      break;
    }
  } while (ch != 'q');

}


--
    ╴╴
  ▔▔\  國度 Charming Shadow Country 
  /\  入境位址 csc241.twbbs.org
\/  位址代碼 203.71.212.241
  \╴╴  來源母國 218-163-192-227.dynamic.hinet.net
  /  ▔▔\  發表時間 2008/03/21 Fri 01:32:50
文章選讀←離開[主題上]主題下(k)上篇(j)下篇S/a搜尋 G串列 TAB精華 ↑↓捲 Pg/Space翻