作者itoc, 信區: itoc
標題[遊戲] rich.c 大富翁
時間03/12/07
作者: itoc (League) 看板: plan
標題: [功能] 大富翁
時間: 2003/12/03 Wed 17:49:04 Updated: 2003/12/22
這個大富翁雖然地圖是一樣的
不過其他的地價及機會命運都是我亂編的 :p
: config.h
#define PIPSHM_KEY 4998 /* 電子雞對戰 */
+ #define RICHSHM_KEY 4997 /* 大富翁 */
: menu.c 適當選單加入
+ "bin/rich.so:main_rich", PERM_BASIC, - M_GAME,
+ "Rich 大富翁",
: game/Makefile
SO = ..... rich.so
: etc/game/rich.land 新增這檔案
: 第一欄是路名
: 第二欄 >10 中一樣的數字表示同一區的,踩到要多收錢
: 第三欄是價格
由此去 -1 0
建國南路 11 500
命運 0 0
建國北路 11 600
付所得稅 -2 0
臺北車站 1 1000
健康路 12 800
機會 0 0
光明路 12 800
五福路 12 1000
坐牢路過 -1 0
自由路 13 1100
電力公司 2 1500
平等路 13 1100
博愛路 13 1200
臺中車站 1 1000
延平三路 14 1400
命運 0 0
延平二路 14 1400
延平一路 14 1500
停車場 -1 0
忠孝路 15 1800
機會 0 0
仁愛路 15 1800
信義路 15 2000
臺南車站 1 1000
民族路 16 2200
民權路 16 2200
自來水廠 2 1500
民生路 16 2500
直接進牢 -3 0
中正路 17 3000
中華路 17 3000
命運 0 0
介壽路 17 3200
高雄車站 1 1000
機會 0 0
新生南路 18 3500
付所得稅 -2 0
新生北路 18 4000
: src/game/rich.c 新增這檔案
/*-------------------------------------------------------*/
/* rich.c ( NTHU CS MapleBBS Ver 3.10 ) */
/*-------------------------------------------------------*/
/* target : 大富翁 */
/* create : 02/07/01 */
/* update : 03/07/14 */
/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */
/*-------------------------------------------------------*/
#include "bbs.h"
#ifdef HAVE_GAME
#define MAX_RICHUSER 10 /* 使用者人數上限,最大可設到 26
(否則英文字母會不夠用) */
#define MAX_LAND 40 /* 全部有 40 塊地 */
typedef struct
{
char userid[IDLEN + 1]; /* ID */
int lose; /* 1: 輸了 */
int money; /* 錢 */
int pos; /* 位置 (0~MAX_LAND-1 分別代表 由此去~新生北路) */
} RICH_PLAYER;
typedef struct
{
char name[9]; /* 土地名 */
int owner; /* 土地擁有者 */
int district; /* >0:地段編號(可購買) >10:一般建地
1:車站 2:電廠水廠 0:機會命運
-1:路過 -2:付稅 -3:坐牢 */
int cost; /* 土地價值 */
int floor; /* 樓層 */
} RICH_LAND;
typedef struct
{
int numuser; /* 本桌目前有幾人 */
int maxuser; /* 本桌最多容納幾人 */
int nowturn; /* 現在輪到誰 */
int numlose; /* 有幾個人倒閉了 */
RICH_PLAYER player[MAX_RICHUSER];
RICH_LAND land[MAX_LAND]; /* 0~39 這些地的狀態 */
} RICH_STRUCT;
static RICH_STRUCT *ri;
static int mynum; /* 我是第幾個玩家 */
static RICH_PLAYER *myrp;
/*-------------------------------------------------------*/
/* 計算罰金 */
/*-------------------------------------------------------*/
static int
count_pay(rl)
RICH_LAND *rl;
{
int i, pay;
RICH_LAND *rlp;
pay = 0;
for (i = 0; i < MAX_LAND; i++)
{
rlp = &ri->land[i];
/* 同區段同主人,罰金要加錢 */
if (rlp->district == rl->district && rlp->owner == rl->owner)
pay += rlp->cost * rlp->floor / 20;
}
return pay;
}
/*-------------------------------------------------------*/
/* 玩家函式 */
/*-------------------------------------------------------*/
static void
rp_init()
{
ri->numuser++;
/* 每個人一開始的狀態 */
myrp = &ri->player[mynum];
strcpy(myrp->userid, cuser.userid);
myrp->lose = 0;
myrp->money = 10000;
myrp->pos = 0;
}
static void
rp_exit()
{
ri->numuser--;
/* 恢復初始狀態 */
myrp->userid[0] ='\0';
}
static int /* 0:繼續玩 -1:輸了*/
rp_play()
{
int pay;
char msg[80];
RICH_PLAYER *rp;
RICH_LAND *rl;
myrp->pos += rnd(6) + 1; /* 每次走 1~6 格 */
myrp->pos %= MAX_LAND;
rl = &ri->land[myrp->pos];
if (rl->owner >= 0)
{
if (rl->owner != mynum) /* 別人的地盤 */
{
rp = &ri->player[rl->owner];
pay = count_pay(rl);
rp->money += pay;
myrp->money -= pay;
sprintf(msg, "您來到了[%s],這是 %s 的地盤,得付他 %d 元",
rl->name, rp->userid, pay);
vmsg(msg);
}
else /* 我的地盤 */
{
if (rl->district > 10)
{
if (myrp->money >= rl->cost)
{
if (rl->floor < 5)
{
sprintf(msg, "您來到了[%s],這是自已的地,要投資建設嗎(Y/N)?[N] ",
rl->name);
if (vans(msg) == 'y')
{
myrp->money -= rl->cost;
rl->floor++;
vmsg("您建設了這塊地");
}
else
{
vmsg("您放棄建設這塊地");
}
}
else
{
sprintf(msg, "您來到了[%s],這塊地已經五層樓高了", rl->name);
vmsg(msg);
}
}
else
{
sprintf(msg, "嗚嗚,[%s]是自己的地,可是您沒錢建設", rl->name);
vmsg(msg);
}
}
else
{
sprintf(msg, "您來到了自己的地盤[%s]", rl->name);
vmsg(msg);
}
}
}
else
{
if (rl->district > 0) /* 可購買的地段 */
{
if (myrp->money >= rl->cost)
{
sprintf(msg, "您來到了[%s],這是沒有人的地,要買下來嗎(Y/N)?[N] ",
rl->name);
if (vans(msg) == 'y')
{
myrp->money -= rl->cost;
rl->owner = mynum;
vmsg("您買下了這塊地");
}
else
{
vmsg("您放棄購買這塊地");
}
}
else
{
sprintf(msg, "嗚嗚,[%s]是沒有人的地,可是您沒錢買", rl->name);
vmsg(msg);
}
}
else if (rl->district == -1) /* 路過 */
{
sprintf(msg, "您來到了[%s],什麼事都沒發生", rl->name);
vmsg(msg);
}
else if (rl->district == -2) /* 扣稅 */
{
myrp->money = myrp->money >> 1;
sprintf(msg, "您來到了[%s],身上的錢被站長搶了一半", rl->name);
vmsg(msg);
}
else if (rl->district == -3) /* 坐牢 */
{
sprintf(msg, "您來到了[%s],被記三支大過勒令退學,輸了", rl->name);
vmsg(msg);
return -1;
}
else /* 機會命運 */
{
sprintf(msg, "您來到了[%s],試試自己的手氣", rl->name);
vmsg(msg);
/* 隨便寫的 :p */
switch (rnd(3))
{
case 0:
myrp->money += 100;
vmsg("考試考 100 分,得到獎學金 100 元 (學校很窮)");
break;
case 1:
myrp->money -= 1000;
vmsg("走路踩到香蕉皮跌倒,付醫藥費 1000 元 (醫院很黑)");
break;
case 2:
myrp->money = 0;
vmsg("遇到強盜,把身上的錢都搶光了");
break;
}
}
}
if (myrp->money < 0)
{
ri->numlose++;
myrp->lose = 1;
vmsg("哇哇,您沒錢了宣告倒閉,輸了");
return -1;
}
return 0;
}
/*-------------------------------------------------------*/
/* 土地函式 */
/*-------------------------------------------------------*/
static void
rl_init()
{
int i;
char district[10], cost[10];
FILE *fp;
RICH_LAND *rl;
if (!(fp = fopen("etc/game/rich.land", "r")))
return;
for (i = 0; i < MAX_LAND; i++)
{
rl = &ri->land[i];
fscanf(fp, "%s %s %s", rl->name, district, cost);
rl->owner = -1;
rl->district = atoi(district);
rl->cost = atoi(cost);
rl->floor = 1;
}
fclose(fp);
}
static void
rl_clear() /* 將自己的土地歸公有 */
{
int i;
RICH_LAND *rl;
for (i = 0; i < MAX_LAND; i++)
{
rl = &ri->land[i];
if (rl->owner == mynum)
{
rl->owner = -1;
rl->floor = 1;
}
}
}
/*-------------------------------------------------------*/
/* 大富翁函式 */
/*-------------------------------------------------------*/
static int /* -1:失敗 >=0:我是第幾個玩家 */
rich_initshm()
{
int num, max;
char ans[5], buf[80];
ri = shm_new(RICHSHM_KEY, sizeof(*ri));
if (shmget(RICHSHM_KEY, sizeof(*ri), 0) < 0)
ri->numuser = 0;
num = ri->numuser;
if (num > MAX_RICHUSER)
{
vmsg("抱歉,桌長設定中,請稍候");
return -1;
}
if (!num) /* 第一個進入的人是桌長 */
{
memset(ri, 0, sizeof(RICH_STRUCT));
ri->numuser = MAX_RICHUSER + 1; /* 桌長設定中 */
sprintf(buf, "幾個人要玩(2~%d)? ", MAX_RICHUSER);
vget(b_lines, 0, buf, ans, 3, DOECHO);
max = atoi(ans);
ri->numuser = 0; /* 桌長設定完成 */
if (max < 2 || max > MAX_RICHUSER)
return -1;
ri->maxuser = max;
}
else /* 桌內已經有人,找一個空位 */
{
max = ri->maxuser;
for (num = 1; num < max; num++) /* 第 0 個位子是桌長 */
{
if (!ri->player[num].userid[0])
break;
}
if (num == max) /* 找不到空位 */
{
vmsg("抱歉,桌內已滿,下次請早");
#if 1 /* 如果確定出錯了,站長可以清桌 */
if (HAS_PERM(PERM_SYSOP) && vans("站長要清桌踢人(Y/N)?[N] ") =='y')
ri->numuser = 0;
#endif
return -1;
}
}
mynum = num;
rp_init();
rl_init();
}
static int /* 0:已滿桌 -1:離開 */
rich_wait() /* 等待滿桌 */
{
int num, max, fd;
struct timeval tv = {1, 0};
num = -1;
max = ri->maxuser;
do /* 查人數是否足夠 */
{
if (num != ri->numuser) /* 有變動才 refresh */
{
move(b_lines, 0);
clrtoeol();
prints("目前有 %d/%d 個玩家,等待其他的使用者加入,按 q 離開",
ri->numuser, max);
refresh();
num = ri->numuser;
}
fd = 1;
if (select(1, (fd_set *) &fd, NULL, NULL, &tv) > 0)
{
if (vkey() == 'q')
{
rp_exit();
return -1;
}
}
} while (num < max);
return 0;
}
static void
rich_display()
{
clear();
move(0, 0);
outs(" 免費 │忠孝│機會│仁愛│信義│臺南│民族│民權│自來│民生│ 直 接 \n");
outs(" 停車場 │ 路 │ │ 路 │ 路 │車站│ 路 │ 路 │水廠│ 路 │ 進 牢 \n");
outs(" ────┼──┴──┴──┴──┴──┴──┴──┴──┴──┼────\n");
outs(" 延平一路│ │中 正 路\n");
outs(" ────┤ ├────\n");
outs(" 延平二路│ │中 華 路\n");
outs(" ────┤ ├────\n");
outs(" 命 運│ │命 運\n");
outs(" ────┤ ├────\n");
outs(" 延平三路│ │介 壽 路\n");
outs(" ────┤ ├────\n");
outs(" 臺中車站│ ─┤↑命令區├──┤ ├──┤ ├── │高雄車站\n");
outs(" ────┤ ├────\n");
outs(" 博 愛 路│ │機 會\n");
outs(" ────┤ ├────\n");
outs(" 平 等 路│ │新生南路\n");
outs(" ────┤ ├────\n");
outs(" 電力公司│ │付所得稅\n");
outs(" ────┤ → ├────\n");
outs(" 自 由 路│ │新生北路\n");
outs(" ────┼──┬──┬──┬──┬──┬──┬──┬──┬──┼────\n");
outs(" 坐 牢 │五福│光明│機會│健康│臺北│付所│建國│命運│建國│由 此 去\n");
outs(" 路 過 │ 路 │ 路 │ │ 路 │車站│得稅│北路│ │南路│ \n");
}
static void
rich_play()
{
int nowturn, nexturn, wait, fd;
struct timeval tv = {1, 0};
/* 開始繞圈圈了 */
srand(time(NULL) - cuser.userno); /* 讓所有人的 seed 都不同 */
for (;;)
{
/* 輪到別人 */
wait = 0;
nowturn = -1;
while (mynum != ri->nowturn)
{
if (nowturn != ri->nowturn) /* 有變動才 refresh */
{
move(b_lines, 0);
clrtoeol();
nowturn = ri->nowturn;
prints("目前輪到 %c. %s", 'A' + nowturn, ri->player[nowturn].userid);
refresh();
}
fd = 1;
select(1, (fd_set *) &fd, NULL, NULL, &tv);
if (++wait > 300)
{
ri->numuser = 0;
vmsg("有人太久未完成行動,應該是斷線了,遊戲停止進行");
return;
}
}
/* 輪到自己 */
if (ri->numlose == ri->numuser - 1)
{
vmsg("哇哇,其他人都倒閉了,您獲勝了");
ri->numuser = 0;
return;
}
outz("請按任意鍵擲骰子\033[5m...\033[m");
vkey();
if ((fd = rp_play()) < 0)
rl_clear();
/* 換下一個還沒輸的人 */
for (nexturn = ri->nowturn;;)
{
nexturn = (nexturn == ri->maxuser - 1) ? 0 : nexturn + 1;
if (!((&ri->player[nexturn])->lose))
break;
}
ri->nowturn = nexturn;
if (fd < 0) /* 我輸了 */
return;
}
}
/*-------------------------------------------------------*/
/* 主程式 */
/*-------------------------------------------------------*/
int
main_rich()
{
if (cutmp->status & STATUS_COINLOCK)
{
vmsg(MSG_COINLOCK);
return XEASY;
}
if (rich_initshm() < 0)
return XEASY;
if (rich_wait() < 0)
return XEASY;
rich_display();
rich_play();
return 0;
}
#endif
--
□ 本文章由 itoc 從 pc512-2.EE.NCTU.edu.tw 發表