作者Iuu.bbs@bupt.cn-bbs.org (麥籽) 看板: plan
標題[功能]殺人遊戲(警察與殺手)
時間真情流露 (Wed, 07 May 2003 13:20:23 +0800 (CST)) Updated: 2004/10/30
不知道大家是否玩過警察與殺手的遊戲,大概說起來,
是一個多人的鬥智遊戲。可以通過使用bbs的聊天室來完成,
當然,多個人聚在一起現場遊戲也很有氣氛。
下面是需要改動的代碼,好在改動的文件并不多,并且
所有代碼都是在 #ifdef HAVE_KILL_GAME #endif 中的。后
面會粘貼相關的遊戲規則。需改動的文件有:
config.h chatd.c xchatd.c
coded by esp @ 真情流露
: config.h
#define LOG_TALK /* lkchu.981201: 聊天記錄處理 */
+ #define HAVE_KILL_GAME /* esp.030414: 是否提供殺手遊戲 */
: chat.c:chat_recv()
else if (fd == 't')
{
str_ncpy(chatopic, str, sizeof(chatopic));
chat_topic();
}
#ifdef HAVE_KILL_GAME
else if (fd == 'k') /* esp: only send /k on entering a kill-game room */
{
char temp[10];
for (fd = 2; fd < stop_line; fd++)
{
move(fd,0);
clrtoeol();
}
sscanf(str, "%s", temp);
chatline = atoi(temp);
move(chatline, 0);
}
else if (fd == 'u') /* esp: refresh the top user table */
{
char temp[10];
sscanf(str, "%s", temp);
fd = atoi(temp);
str = strchr(str, ' ') + 1;
cursor_save();
move(fd, 0);
outs(str);
cursor_restore();
}
#endif
: xchatd.c
在 maple/xchatd.c 中增加的代碼數量比較多,也是全部
定義在 #define HAVE_KILL_GAME #endif 中的。
對 xchatd.c 中增加的代碼有28處,一一列出來,請搜索
#define HAVE_KILL_GAME,把這部分的代碼加到自己的 xchatd.c 中。
注意,如果直接下載的話,有些代碼因為超過了80字,所
以bbs自動做了回行,這部分使用的時候,要修正。
/*-------------------------------------------------------*/
/* xchatd.c ( NTHU CS MapleBBS Ver 3.00 ) */
/*-------------------------------------------------------*/
/* target : super KTV daemon for chat server */
/* create : 95/03/29 */
/* update : 97/10/20 */
/*-------------------------------------------------------*/
#include "bbs.h"
#include "xchat.h"
#ifdef HAVE_KILL_GAME
typedef struct
{
int won;
int lost;
int dropped;
int nreserved;
int lastgame; /* win or lose or drop */
time_t tlastgame;
time_t treserved;
} KILL_STATE;
#endif
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <fcntl.h>
#if defined(AIX) || defined(HIGHGCC)
#include <sys/time.h>
#else
#include <time.h>
#endif /* hightman.011028: Redhat7.x有點怪 :) */
#include <sys/resource.h>
#ifdef SOLARIS
extern char *sys_errlist[];
#endif
#define SERVER_USAGE
#define WATCH_DOG
#undef DEBUG /* 程式除錯之用 */
#undef MONITOR /* 監督 chatroom 活動以解決糾紛 */
#undef STAND_ALONE /* 不搭配 BBS 獨立執行 */
#ifdef DEBUG
#define MONITOR
#endif
static int gline;
#ifdef WATCH_DOG
#define MYDOG gline = __LINE__
#else
#define MYDOG /* NOOP */
#endif
#define CHAT_PIDFILE "run/chat.pid"
#define CHAT_LOGFILE "run/chat.log"
#define CHAT_INTERVAL (60 * 30)
#define SOCK_QLEN 3
/* name of the main room (always exists) */
#define MAIN_NAME "main"
#define MAIN_TOPIC "萍水相逢自有緣"
#define ROOM_LOCKED 0x01
#define ROOM_SECRET 0x02
#define ROOM_OPENTOPIC 0x04
/* fuse.991210: 沒有動作,沒有系統訊息的聊天室 */
#define ROOM_QUIET 0x08
#define ROOM_INTERVIEW 0x10
/* esp.030414: 殺人遊戲 */
#ifdef HAVE_KILL_GAME
#define ROOM_KILLGAME 0x20
#define ROOM_KILL_STARTED 0x40
#define ROOM_KILL_WAITDROP 0x80
#define ROOM_KILL_DISCUSS 0x100
#define ROOM_KILL_NOGHOST 0x200
#define ROOM_KILL_POLICE 0x400
#define ROOM_KILL_NOPOLICE 0x800
#define ROOM_KILL_STRPOLICE 0x1000
#endif
#define ROOM_ALL (NULL)
#define LOCKED(room) (room->rflag & ROOM_LOCKED)
#define SECRET(room) (room->rflag & ROOM_SECRET)
#define OPENTOPIC(room) (room->rflag & ROOM_OPENTOPIC)
#define QUIET(room) (room->rflag & ROOM_QUIET)
#define INTERVIEW(room) (room->rflag & ROOM_INTERVIEW)
#define RESTRICTED(usr) (usr->uflag == 0) /* guest */
#define CHATSYSOP(usr) (usr->uflag & (PERM_SYSOP | PERM_CHATROOM))
#define PERM_ROOMOP PERM_CHAT /* Thor: 借 PERM_CHAT為 PERM_ROOMOP */
#define PERM_CHATOP PERM_DENYCHAT /* Thor: 借 PERM_DENYCHAT為 PERM_CHATOP */
/* #define ROOMOP(usr) (usr->uflag & ( PERM_ROOMOP | PERM_SYSOP | PERM_CHATROO
M)) */
/* Thor.980603: PERM_CHATROOM改為 default 沒有 roomop, 但可以自己取得 chatop*/
#define ROOMOP(usr) (usr->uflag & (PERM_ROOMOP|PERM_CHATOP))
#define CLOAK(usr) (usr->uflag & PERM_CLOAK)
#ifdef HAVE_KILL_GAME
#define KILL_ROLE_MASK 0x0F
#define KILL_NONE 0
#define KILL_JUDGE 1
#define KILL_POLICE 2
#define KILL_KILLER 3
#define KILL_NORMAL 4
#define KILL_ROLE(x) (x->killflag & KILL_ROLE_MASK)
#define KILL_KILLED 0x10
#define KILL_KNOCKOUT 0x20
#define KILL_VOTED 0x40
#define KILL_TALKED 0x80 // esp: use it for talk & look around
#define KILL_DROPED 0x100 // esp: for reconnect...
#define KILL_QUERYED 0x200 // esp: police use this for done,killer use this for
having been queryed
/* kill game status */
#define KILL_NOT_START 0
#define KILL_NIGHT_KILLER 1
#define KILL_NIGHT_POLICE 2
#define KILL_DAY_MURDERED 3
#define KILL_DAY_TALK 4
#define KILL_DAY_VOTE 5
#define KILL_AFTERDAY 6
#define KILL_BEFORENIGHT 7
/* kill user states */
#define KILL_USER_UNKNOWN 0
#define KILL_USER_KILLER 1
#define KILL_USER_KILLED_KILLER 2
#define KILL_USER_POLICE 3
#define KILL_USER_KILLED_POLICE 4
#define KILL_USER_MISKILLED_POLICE 5
#define KILL_USER_NORMAL 6
#define KILL_USER_KILLED_NORMAL 7
#define KILL_USER_MISKILLED_NORMAL 8
#define KILL_USER_JUDGE 9
#define KILL_USER_JUSTKILLED 10
/* states only for the judge */
#define KILL_JUDGE_FRESH 0
#define KILL_JUDGE_KILLED 1 /* esp: prevent judge from kill more at one round o
r no kill at all */
static char userkillstates[11][11] =
{
"目前未知",
"殺手",
"被殺殺手",
"警察",
"被殺警察",
"被冤殺警察",
"平民",
"被殺平民",
"被冤殺平民",
"法官",
"被殺"
};
static char userkillstatecolors[11][10] = {
"\033[37m",
"\033[1;31m",
"\033[4;31m",
"\033[1;32m",
"\033[4;32m",
"\033[1;4;32m",
"\033[1;33m",
"\033[4;33m",
"\033[1;4;33m",
"\033[30;47m",
"\033[4m"
};
#endif
/* ----------------------------------------------------- */
/* ChatRoom data structure */
/* ----------------------------------------------------- */
typedef struct ChatRoom ChatRoom;
typedef struct ChatUser ChatUser;
typedef struct UserList UserList;
typedef struct ChatCmd ChatCmd;
typedef struct ChatAction ChatAction;
struct ChatUser
{
ChatUser *unext;
ChatRoom *room;
UserList *ignore;
int sock; /* user socket */
int userno;
int uflag;
int clitype; /* Xshadow: client type. 1 for common client,
* 0 for bbs only client */
#ifdef HAVE_KILL_GAME
int killflag;
int killstate;
int votenum;
char killid[16];
time_t tkillbegin;
#endif
time_t tbegin;
time_t uptime;
int sno;
int xdata;
int retry;
int isize; /* current size of ibuf */
char ibuf[80]; /* buffer for non-blocking receiving */
char userid[IDLEN + 1]; /* real userid */
char chatid[9]; /* chat id */
char rhost[30]; /* host address */
};
struct ChatRoom
{
ChatRoom *next, *prev;
UserList *invite;
char name[IDLEN];
char topic[48]; /* Let the room op to define room topic */
int rflag; /* ROOM_LOCKED, ROOM_SECRET, ROOM_OPENTOPIC */
#ifdef HAVE_KILL_GAME
int killstatus;
/* esp: the judge always only one */
int policenum;
int killernum;
int normalnum;
ChatUser *currenttalker;
time_t tvotebegin;
#endif
int occupants; /* number of users in room */
};
struct UserList
{
UserList *next;
int userno;
char userid[0];
};
struct ChatCmd
{
char *cmdstr;
void (*cmdfunc) ();
int exact;
};
static ChatRoom mainroom, *roompool;
static ChatUser *mainuser, *userpool;
static fd_set mainfset;
static int totaluser; /* current number of connections */
static struct timeval zerotv; /* timeval for selecting */
static int common_client_command;
/* fuse.991211:被采訪人 */
static char interviewer[20];
#ifdef STAND_ALONE
static int userno_inc = 0; /* userno auto-incrementer */
#endif
static char msg_not_op[] = "◆ 您不是這間聊天室的 Op";
static char msg_no_such_id[] = "◆ 目前沒有人使用 [%s] 這個聊天代號";
static char msg_not_here[] = "◆ [%s] 不在這間聊天室";
#define FUZZY_USER ((ChatUser *) -1)
#ifdef HAVE_KILL_GAME
/* esp: kill game functions */
static void kill_start(ChatUser* cu, char* msg);
static void kill_end(ChatUser* cu, char* msg);
static void kill_parse_start_options(ChatRoom *room, char* msg);
// static void kill_sunrise(ChatUser *cu, char* msg);
// static void kill_sunset(ChatUser *cu, char* msg);
// static void kill_vote(ChatUser *cu, char* msg);
// static void kill_user_vote(ChatUser *cu, char* msg);
// static void kill_clear_vote(ChatUser *cu, char* msg);
static void kill_kill(ChatUser *cu, char* msg);
static int kill_can_talk_between(ChatRoom *room, ChatUser *cu, ChatUser *xuser)
;
static int kill_can_talk(ChatRoom *room, ChatUser *user );
static int kill_get_user_state(ChatRoom *room, ChatUser *cu, ChatUser *user);
static void kill_refresh_table(ChatRoom* room);
static void kill_over(ChatUser *cu, char *msg);
// static void kill_killer_over(ChatRoom *room, ChatUser *cu);
// static void kill_police_over(ChatRoom *room, ChatUser *cu);
static void kill_talk_over(ChatRoom *room, ChatUser *cu);
static int kill_on_user_over(ChatRoom *room);
static ChatUser *kill_get_next_user(ChatRoom *room, ChatUser *cu);
static void kill_check_vote(ChatRoom* room, ChatUser* cu);
static void kill_clear_user_state(ChatRoom* room);
static void kill_on_reconnect(ChatRoom* room);
static void kill_police_query(ChatUser *cu, char* msg);
static void kill_show_next_killer(ChatRoom *room);
static void kill_talk_time_check(ChatRoom *room);
static void kill_vote_time_check(ChatRoom *room);
static ChatUser* kill_auto_vote(ChatRoom *room);
static void kill_kkk(ChatUser *user,char* msg);
static void kill_log_state(ChatUser *user, int nMode);
static void kill_show_state(ChatUser *cu, char *msg);
#endif
/* ----------------------------------------------------- */
/* operation log and debug information */
/* ----------------------------------------------------- */
static FILE *flog;
/* Thor.990211: 統一用 dao library */
#define str_time(t) Btime(t)
#if 0
static char *
str_time(t)
time_t *t;
{
static char buf[20];
struct tm *p;
p = localtime(t);
sprintf(buf, "%02d/%02d %02d:%02d:%02d",
p->tm_mon + 1, p->tm_mday,
p->tm_hour, p->tm_min, p->tm_sec);
return buf;
}
#endif
static void
logit(key, msg)
char *key;
char *msg;
{
time_t now;
struct tm *p;
time(&now);
p = localtime(&now);
fprintf(flog, "%02d/%02d %02d:%02d:%02d %-13s%s\n",
p->tm_mon + 1, p->tm_mday,
p->tm_hour, p->tm_min, p->tm_sec, key, msg);
}
static inline void
log_init()
{
FILE *fp;
/* --------------------------------------------------- */
/* log daemon's PID */
/* --------------------------------------------------- */
if (fp = fopen(CHAT_PIDFILE, "w"))
{
fprintf(fp, "%d\n", getpid());
fclose(fp);
}
flog = fopen(CHAT_LOGFILE, "a");
logit("START", "chat daemon");
}
#ifdef DEBUG
static char chatbuf[256]; /* general purpose buffer */
static void
debug_list(list)
UserList *list;
{
char buf[80];
int i = 0;
if (!list)
{
logit("DEBUG_L", "NULL");
return;
}
while (list)
{
sprintf(buf, "%d) list: %p userno: %d next: %p", i++, list, list->userno, l
ist->next);
logit("DEBUG_L", buf);
list = list->next;
}
logit("DEBUG_L", "end");
}
static void
debug_user()
{
ChatUser *user;
int i;
char buf[80];
sprintf(buf, "mainuser: %p userpool: %p", mainuser, userpool);
logit("DEBUG_U", buf);
for (i = 0, user = mainuser; user; user = user->unext)
{
/* MYDOG; */
sprintf(buf, "%d) %p %-6d %s %s", ++i, user, user->userno, user->userid, us
er->chatid);
logit("DEBUG_U", buf);
}
}
static void
debug_room()
{
ChatRoom *room;
int i;
char buf[80];
i = 0;
room = &mainroom;
sprintf(buf, "mainroom: %p roompool: %p", mainroom, roompool);
logit("DEBUG_R", buf);
do
{
MYDOG;
sprintf(buf, "%d) %p %s %d", ++i, room, room->name, room->occupants);
logit("DEBUG_R", buf);
} while (room = room->next);
}
static void
log_user(cu)
ChatUser *cu;
{
static int log_num;
if (cu)
{
if (log_num > 100 && log_num < 150)
{
sprintf(chatbuf, "%d: %p <%d>", log_num, cu, gline);
logit("travese user ", chatbuf);
}
else if (log_num == 100)
{
sprintf(chatbuf, "BOOM !! at line %d", gline);
logit("travese user ", chatbuf);
}
log_num++;
}
else
log_num = 0;
}
#endif /* DEBUG */
/* ----------------------------------------------------- */
/* string routines */
/* ----------------------------------------------------- */
static int
valid_chatid(id)
char *id;
{
int ch, len;
for (len = 0; ch = *id; id++)
{ /* Thor.980921: 空白為不合理chatid, 怕getnext判斷錯誤等等 */
if (ch == '/' || ch == '*' || ch == ':' || ch ==' ')
return 0;
if (++len > 8)
return 0;
}
return len;
}
#if 0
static void
str_lower(dst, src)
char *dst, *src;
{
int ch;
do
{
ch = *src++;
if (ch >= 'A' && ch <= 'Z')
ch += 0x20;
*dst++ = ch;
} while (ch);
}
static void
str_ncpy(dst, src, n)
char *dst;
char *src;
int n;
{
char *end;
end = dst + n;
do
{
n = (dst == end) ? 0 : *src++;
*dst++ = n;
} while (n);
}
#endif
/* Case Independent strcmp : 1 ==> euqal */
/* Thor.990211: 統一使用dao library */
#define str_equal(s1,s2) (!str_cmp(s1,s2))
#if 0
static int
str_equal(s1, s2)
uschar *s1; /* lower-case (sub)string */
uschar *s2;
{
int c1, c2;
for (;;)
{
c1 = *s1;
c2 = *s2;
if (c2 >= 'A' && c2 <= 'Z')
c2 += 32;
if (c1 != c2)
return 0;
if (!c1)
return 1;
s1++;
s2++;
}
}
#endif
/* ----------------------------------------------------- */
/* match strings' similarity case-insensitively */
/* ----------------------------------------------------- */
/* str_match(keyword, string) */
/* ----------------------------------------------------- */
/* 0 : equal ("foo", "foo") */
/* -1 : mismatch ("abc", "xyz") */
/* ow : similar ("goo", "good") */
/* ----------------------------------------------------- */
static int
str_match(s1, s2)
uschar *s1; /* lower-case (sub)string */
uschar *s2;
{
int c1, c2;
for (;;)
{
c1 = *s1;
c2 = *s2;
if (!c1)
return c2;
if (c2 >= 'A' && c2 <= 'Z')
c2 += 32;
if (c1 != c2)
return -1;
s1++;
s2++;
}
}
/* ----------------------------------------------------- */
/* search user/room by its ID */
/* ----------------------------------------------------- */
static ChatUser *
cuser_by_userid(userid)
char *userid;
{
ChatUser *cu;
char buf[80]; /* Thor.980727: 一次最長才80 */
str_lower(buf, userid);
for (cu = mainuser; cu; cu = cu->unext)
{
if (!cu->userno)
continue;
if (str_equal(buf, cu->userid))
break;
}
return cu;
}
static ChatUser *
cuser_by_chatid(chatid)
char *chatid;
{
ChatUser *cu;
char buf[80]; /* Thor.980727: 一次最長才80 */
str_lower(buf, chatid);
for (cu = mainuser; cu; cu = cu->unext)
{
if (!cu->userno)
continue;
if (str_equal(buf, cu->chatid))
break;
}
return cu;
}
static ChatUser *
fuzzy_cuser_by_chatid(chatid)
char *chatid;
{
ChatUser *cu, *xuser;
int mode;
char buf[80]; /* Thor.980727: 一次最長才80 */
str_lower(buf, chatid);
xuser = NULL;
for (cu = mainuser; cu; cu = cu->unext)
{
if (!cu->userno)
continue;
mode = str_match(buf, cu->chatid);
if (mode == 0)
return cu;
if (mode > 0)
{
if (xuser)
return FUZZY_USER; /* 符合者大於 2 人 */
xuser = cu;
}
}
return xuser;
}
static ChatRoom *
croom_by_roomid(roomid)
char *roomid;
{
ChatRoom *room;
char buf[80]; /* Thor.980727: 一次最長才80 */
str_lower(buf, roomid);
room = &mainroom;
do
{
if (str_equal(buf, room->name))
break;
} while (room = room->next);
return room;
}
/* ----------------------------------------------------- */
/* UserList routines */
/* ----------------------------------------------------- */
static void
list_free(list)
UserList **list;
{
UserList *user, *next;
for (user = *list, *list = NULL; user; user = next)
{
next = user->next;
free(user);
}
}
static void
list_add(list, user)
UserList **list;
ChatUser *user;
{
UserList *node;
char *userid;
int len;
len = strlen(userid = user->userid) + 1;
if (node = (UserList *) malloc(sizeof(UserList) + len))
{
node->next = *list;
node->userno = user->userno;
memcpy(node->userid, userid, len);
*list = node;
}
}
static int
list_delete(list, userid)
UserList **list;
char *userid;
{
UserList *node;
char buf[80]; /* Thor.980727: 輸入一次最長才 80 */
str_lower(buf, userid);
while (node = *list)
{
if (str_equal(buf, node->userid))
{
*list = node->next;
free(node);
return 1;
}
list = &node->next;
}
return 0;
}
static int
list_belong(list, userno)
UserList *list;
int userno;
{
while (list)
{
if (userno == list->userno)
return 1;
list = list->next;
}
return 0;
}
/* ------------------------------------------------------ */
/* non-blocking socket routines : send message to users */
/* ------------------------------------------------------ */
static void
do_send(nfds, wset, msg)
int nfds;
fd_set *wset;
char *msg;
{
int len, sr;
#if 1
/* Thor: for future reservation bug */
zerotv.tv_sec = 0;
zerotv.tv_usec = 0;
#endif
sr = select(nfds + 1, NULL, wset, NULL, &zerotv);
if (sr > 0)
{
len = strlen(msg) + 1;
do
{
if (FD_ISSET(nfds, wset))
{
send(nfds, msg, len, 0);
if (--sr <= 0)
return;
}
} while (--nfds > 0);
}
}
static void
send_to_room(room, msg, userno, number, fromuser)
ChatRoom *room;
char *msg;
int userno;
int number;
ChatUser *fromuser;
{
ChatUser *cu;
fd_set wset;
int sock, max;
int clitype; /* 分為 bbs client 及 common client 兩次處理 */
char *str, buf[256];
for (clitype = (number == MSG_MESSAGE || !number) ? 0 : 1;
clitype < 2; clitype++)
{
FD_ZERO(&wset);
max = -1;
for (cu = mainuser; cu; cu = cu->unext)
{
if (cu->userno && (cu->clitype == clitype) &&
(room == ROOM_ALL || room == cu->room) &&
(!userno || !list_belong(cu->ignore, userno)))
{
#ifdef HAVE_KILL_GAME
if(fromuser != NULL)
{
if(!kill_can_talk_between(room, fromuser,cu))
continue;
}
#endif
sock = cu->sock;
FD_SET(sock, &wset);
if (max < sock)
max = sock;
}
}
if (max <= 0)
continue;
if (clitype)
{
str = buf;
if (*msg)
sprintf(str, "%3d %s", number, msg);
else
sprintf(str, "%3d", number);
}
else
{
str = msg;
}
do_send(max, &wset, str);
}
}
static void
send_to_user(user, msg, userno, number)
ChatUser *user;
char *msg;
int userno;
int number;
{
int sock;
#if 0
if (!user->userno || (!user->clitype && number && number != MSG_MESSAGE))
#endif
/* Thor.980911: 如果查user->userno則在login_user的error message會無法送回 */
if (!user->clitype && number != MSG_MESSAGE)
return;
if ((sock = user->sock) <= 0)
return;
if (!userno || !list_belong(user->ignore, userno))
{
fd_set wset;
char buf[256];
FD_ZERO(&wset);
FD_SET(sock, &wset);
if (user->clitype)
{
if (*msg)
sprintf(buf, "%3d %s", number, msg);
else
sprintf(buf, "%3d", number);
msg = buf;
}
do_send(sock, &wset, msg);
}
}
/* ----------------------------------------------------- */
static void
room_changed(room)
ChatRoom *room;
{
if (room)
{
char buf[256];
sprintf(buf, "= %s %d %d %s",
room->name, room->occupants, room->rflag, room->topic);
send_to_room(ROOM_ALL, buf, 0, MSG_ROOMNOTIFY,NULL);
}
}
static void
user_changed(cu)
ChatUser *cu;
{
if (cu)
{
ChatRoom *room;
char buf[256];
room = cu->room;
sprintf(buf, "= %s %s %s %s%s",
cu->userid, cu->chatid, room->name, cu->rhost,
ROOMOP(cu) ? " Op" : "");
send_to_room(room, buf, 0, MSG_USERNOTIFY,NULL);
}
}
static void
exit_room(user, mode, msg)
ChatUser *user;
int mode;
char *msg;
{
ChatRoom *room;
usint uflag;
char buf[128];
if (!(room = user->room))
return;
uflag = user->uflag;
user->room = NULL;
/* user->uflag &= ~(PERM_ROOMOP | PERM_SYSOP | PERM_CHATROOM); */
user->uflag &= ~PERM_ROOMOP;
/* Thor.980601: 離開房間時只清 room op, 不清 sysop,chatroom,因天生具有 */
if (--room->occupants > 0)
{
char *chatid;
chatid = user->chatid;
switch (mode)
{
case EXIT_LOGOUT:
sprintf(buf, "◆ %s 離開了 ...", chatid);
if (msg && *msg)
{
strcat(buf, ": ");
#if 1
msg[79] = 0; /* Thor:防止太長 */
#endif
strncat(buf, msg, 79);
}
break;
case EXIT_LOSTCONN:
sprintf(buf, "◆ %s 成了斷線的風箏囉", chatid);
break;
case EXIT_KICK:
sprintf(buf, "◆ 哈哈!%s 被踢出去了", chatid);
break;
}
/* fuse.991210: QUIET模式下不顯示離開訊息 */
if ((!CLOAK(user)) && (!INTERVIEW(room)))
send_to_room(room, buf, 0, MSG_MESSAGE,NULL);
sprintf(buf, "- %s", user->userid);
send_to_room(room, buf, 0, MSG_USERNOTIFY,NULL);
room_changed(room);
#ifdef HAVE_KILL_GAME
if(room->rflag & ROOM_KILL_STARTED)
{
if (mode == EXIT_LOSTCONN || mode == EXIT_LOGOUT)
kill_log_state(user, 3); // 3 for DROP
send_to_room(room,"\033[1;31m唉,沒辦法,重新開始吧。\033[m", 0, MSG_MESSAGE, NULL);
send_to_room(room,"\033[1;33m$$ 這一輪的遊戲被提前結束了\033[m", 0, MSG_MESSAGE, NULL);
room->rflag &= ~ROOM_KILL_STARTED;
room->killstatus = KILL_NOT_START;
kill_refresh_table(room);
kill_clear_user_state(room);
}
#endif
}
else if (room != &mainroom)
{
ChatRoom *next;
fprintf(flog, "room-\t[%d] %s\n", user->sno, room->name);
sprintf(buf, "- %s", room->name);
room->prev->next = next = room->next;
if (next)
next->prev = room->prev;
list_free(&room->invite);
/* free(room); */
/* 回收 */
room->next = roompool;
roompool = room;
send_to_room(ROOM_ALL, buf, 0, MSG_ROOMNOTIFY,NULL);
}
}
/* ----------------------------------------------------- */
/* chat commands */
/* ----------------------------------------------------- */
#ifndef STAND_ALONE
/* ----------------------------------------------------- */
/* BBS server side routines */
/* ----------------------------------------------------- */
/* static */
int
acct_load(acct, userid)
ACCT *acct;
char *userid;
{
int fd;
usr_fpath((char *) acct, userid, FN_ACCT);
fd = open((char *) acct, O_RDONLY);
if (fd >= 0)
{
read(fd, acct, sizeof(ACCT));
close(fd);
}
return fd;
}
static void
chat_query(cu, msg)
ChatUser *cu;
char *msg;
{
FILE *fp;
ACCT acct;
char buf[256];
/* Thor.980617: 可先查是否為空字串 */
if (*msg && acct_load(&acct, msg) >= 0)
{
sprintf(buf, "%s(%s) 共上站 %d 次,文章 %d 篇",
acct.userid, acct.username, acct.numlogins, acct.numposts);
send_to_user(cu, buf, 0, MSG_MESSAGE);
sprintf(buf, "最近(%s)從(%s)上站", Btime(&acct.lastlogin),
(acct.lasthost[0] ? acct.lasthost : "外太空"));
send_to_user(cu, buf, 0, MSG_MESSAGE);
usr_fpath(buf, acct.userid, "plans");
if (fp = fopen(buf, "r"))
{
int i;
i = 0;
while (fgets(buf, 255, fp) && buf[0])
{
buf[strlen(buf) - 1] = 0;
send_to_user(cu, buf, 0, MSG_MESSAGE);
if (++i >= MAXQUERYLINES)
break;
}
fclose(fp);
}
}
else
{
sprintf(buf, msg_no_such_id, msg);
send_to_user(cu, buf, 0, MSG_MESSAGE);
}
}
#endif
static void
chat_clear(cu, msg)
ChatUser *cu;
char *msg;
{
if (cu->clitype)
send_to_user(cu, "", 0, MSG_CLRSCR);
else
send_to_user(cu, "/c", 0, MSG_MESSAGE);
}
static void
chat_date(cu, msg)
ChatUser *cu;
char *msg;
{
time_t thetime;
char buf[128];
time(&thetime);
sprintf(buf, "◆ 標準時間: %s", Btime(&thetime));
send_to_user(cu, buf, 0, MSG_MESSAGE);
}
static void
chat_topic(cu, msg)
ChatUser *cu;
char *msg;
{
ChatRoom *room;
char *topic, buf[128];
room = cu->room;
if (!ROOMOP(cu) && !OPENTOPIC(room))
{
send_to_user(cu, msg_not_op, 0, MSG_MESSAGE);
return;
}
if (*msg == '\0')
{
send_to_user(cu, "※ 請指定話題", 0, MSG_MESSAGE);
return;
}
topic = room->topic;
/* str_ncpy(topic, msg, sizeof(room->topic) - 1); */
str_ncpy(topic, msg, sizeof(room->topic));
/* Thor.980921: str_ncpy 已含 0之空間 */
#ifdef HAVE_KILL_GAME
if (room->rflag & ROOM_KILLGAME)
strcat(topic, "K");
#endif
if (cu->clitype)
{
send_to_room(room, topic, 0, MSG_TOPIC,NULL);
}
else
{
sprintf(buf, "/t%s", topic);
send_to_room(room, buf, 0, MSG_MESSAGE,NULL);
}
room_changed(room);
if (!CLOAK(cu))
{
sprintf(buf, "◆ %s 將話題改為 %s", cu->chatid, topic);
send_to_room(room, buf, 0, MSG_MESSAGE,NULL);
}
}
static void
chat_version(cu, msg)
ChatUser *cu;
char *msg;
{
char buf[80];
sprintf(buf, "%d %d", XCHAT_VERSION_MAJOR, XCHAT_VERSION_MINOR);
send_to_user(cu, buf, 0, MSG_VERSION);
}
static void
chat_nick(cu, msg)
ChatUser *cu;
char *msg;
{
char *chatid, *str, buf[128];
ChatUser *xuser;
#ifdef HAVE_KILL_GAME
if(cu->room->rflag & ROOM_KILL_STARTED)
{
send_to_user(cu, "※ 殺手遊戲進行中,不能更改ID", 0, MSG_MESSAGE);
return;
}
#endif
chatid = nextword(&msg);
chatid[8] = '\0';
if (!valid_chatid(chatid))
{
send_to_user(cu, "※ 這個聊天代號是不正確的", 0, MSG_MESSAGE);
return;
}
xuser = cuser_by_chatid(chatid);
if (xuser != NULL && xuser != cu)
{
send_to_user(cu, "※ 已經有人捷足先登囉", 0, MSG_MESSAGE);
return;
}
str = cu->chatid;
/* fuse.991210: 改代號這種事quiet模式下不要顯示了 */
if ((!CLOAK(cu)) && (!INTERVIEW(cu->room)))
{
sprintf(buf, "※ %s 將聊天代號改為 %s", str, chatid);
send_to_room(cu->room, buf, cu->userno, MSG_MESSAGE,NULL);
}
strcpy(str, chatid);
user_changed(cu);
if (cu->clitype)
{
send_to_user(cu, chatid, 0, MSG_NICK);
}
else
{
sprintf(buf, "/n%s", chatid);
send_to_user(cu, buf, 0, MSG_MESSAGE);
}
}
static void
chat_list_rooms(cuser, msg)
ChatUser *cuser;
char *msg;
{
ChatRoom *cr, *room;
char buf[128];
int mode;
if (RESTRICTED(cuser))
{
send_to_user(cuser, "※ 您沒有權限列出現有的聊天室", 0, MSG_MESSAGE);
return;
}
mode = common_client_command;
if (mode)
send_to_user(cuser, "", 0, MSG_ROOMLISTSTART);
else
send_to_user(cuser, " 談天室名稱 │人數│話題 ", 0,
MSG_MESSAGE);
room = cuser->room;
cr = &mainroom;
do
{
if ((cr == room) || !SECRET(cr) || CHATSYSOP(cuser))
{
if (mode)
{
sprintf(buf, "%s %d %d %s",
cr->name, cr->occupants, cr->rflag, cr->topic);
send_to_user(cuser, buf, 0, MSG_ROOMLIST);
}
else
{
sprintf(buf, " %-12s│%4d│%s", cr->name, cr->occupants, cr->topic);
if (LOCKED(cr))
strcat(buf, " [鎖住]");
if (SECRET(cr))
strcat(buf, " [秘密]");
if (OPENTOPIC(cr))
strcat(buf, " [話題]");
send_to_user(cuser, buf, 0, MSG_MESSAGE);
}
}
} while (cr = cr->next);
if (mode)
send_to_user(cuser, "", 0, MSG_ROOMLISTEND);
}
static void
chat_do_user_list(cu, msg, theroom)
ChatUser *cu;
char *msg;
ChatRoom *theroom;
{
ChatRoom *myroom, *room;
ChatUser *user;
int start, stop, curr, mode; /* , uflag; */
char buf[128];
curr = 0; /* Thor.980619: initialize curr */
start = atoi(nextword(&msg));
stop = atoi(nextword(&msg));
mode = common_client_command;
if (mode)
send_to_user(cu, "", 0, MSG_USERLISTSTART);
else
send_to_user(cu, " 聊天代號│使用者代號 │聊天室 ", 0,
MSG_MESSAGE);
myroom = cu->room;
/* Thor.980717: 需要先排除 cu->userno == 0 的狀況嗎? */
for (user = mainuser; user; user = user->unext)
{
/*
if (!cu->userno)
continue;
*/ /* Thor.980717: 既然 cu 都空了那還進來幹麼? */
if (!user->userno)
continue;
room = user->room;
if ((theroom != ROOM_ALL) && (theroom != room))
continue;
#if 0
uflag = user->uflag;
if ((myroom != room) && (!uflag ||
(room && SECRET(room) && !(uflag & (PERM_SYSOP | PERM_CHATROOM)))))
continue;
if ((uflag & PERM_CLOAK) && (user != cu) &&
!(uflag & (PERM_SYSOP | PERM_CHATROOM)))
continue;
#endif
/* Thor.980717:上述logic有誤 */
/* Thor.980717: viewer check */
if ((myroom != room) && (RESTRICTED(cu) ||
(room && SECRET(room) && !CHATSYSOP(cu))))
continue;
/* Thor.980717: viewee check */
if (CLOAK(user) && (user != cu) && !CHATSYSOP(cu))
continue;
/* Thor.980717:重寫*/
curr++;
if (start && curr < start)
continue;
else if (stop && (curr > stop))
break;
if (mode)
{
if (!room)
continue; /* Xshadow: 還沒進入任何房間的就不列出 */
sprintf(buf, "%s %s %s %s",
user->chatid, user->userid, room->name, user->rhost);
/* Thor.980603: PERM_CHATROOM改為 default 沒有 roomop, 但可以自己取得 */
/* if (uflag & (PERM_ROOMOP | PERM_SYSOP | PERM_CHATROOM)) */
if (ROOMOP(user))
strcat(buf, " Op");
}
else
{
sprintf(buf, " %-8s│%-12s│%s",
user->chatid, user->userid, room ? room->name : "[在門口徘徊]");
/* Thor.980603: PERM_CHATROOM改為 default 沒有 roomop, 但可以自己取得 */
/* if (uflag & (PERM_ROOMOP | PERM_SYSOP | PERM_CHATROOM)) */
/* if (uflag & (PERM_ROOMOP|PERM_CHATOP)) */
if (ROOMOP(user)) /* Thor.980602: 統一用法 */
strcat(buf, " [Op]");
}
send_to_user(cu, buf, 0, mode ? MSG_USERLIST : MSG_MESSAGE);
}
if (mode)
send_to_user(cu, "", 0, MSG_USERLISTEND);
}
static void
chat_list_by_room(cu, msg)
ChatUser *cu;
char *msg;
{
ChatRoom *whichroom;
char *roomstr, buf[128];
roomstr = nextword(&msg);
if (!*roomstr)
{
whichroom = cu->room;
}
else
{
if (!(whichroom = croom_by_roomid(roomstr)))
{
sprintf(buf, "※ 沒有 [%s] 這個聊天室", roomstr);
send_to_user(cu, buf, 0, MSG_MESSAGE);
return;
}
if (whichroom != cu->room && SECRET(whichroom) && !CHATSYSOP(cu))
{
send_to_user(cu, "※ 無法列出在秘密聊天室的使用者", 0, MSG_MESSAGE);
return;
}
}
chat_do_user_list(cu, msg, whichroom);
}
static void
chat_list_users(cu, msg)
ChatUser *cu;
char *msg;
{
chat_do_user_list(cu, msg, ROOM_ALL);
}
static void
chat_chatroom(cu, msg)
ChatUser *cu;
char *msg;
{
if (common_client_command)
send_to_user(cu, "真情流露聊天廣場", 0, MSG_CHATROOM);
}
static void
chat_map_chatids(cu, whichroom)
ChatUser *cu; /* Thor: 還沒有作不同間的 */
ChatRoom *whichroom;
{
int c;
ChatRoom *myroom, *room;
ChatUser *user;
char buf[128];
myroom = cu->room;
#ifdef HAVE_KILL_GAME
if (whichroom != ROOM_ALL && whichroom->rflag & (ROOM_KILLGAME | ROOM_KILL_
STARTED) )
send_to_user(cu,
" 聊天代號 角色 │ 聊天代號 角色 │ 聊天代號 角色 ", 0,
MSG_MESSAGE);
else
#endif
send_to_user(cu,
" 聊天代號 使用者代號 │ 聊天代號 使用者代號 │ 聊天代號 使用者代號 ", 0,
MSG_MESSAGE);
for (c = 0, user = mainuser; user; user = user->unext)
{
if (!cu->userno)
continue;
room = user->room;
if (whichroom != ROOM_ALL && whichroom != room)
continue;
if (myroom != room)
{
if (RESTRICTED(cu) || /* Thor: 要先check room 是不是空的 */
(room && SECRET(room) && !CHATSYSOP(cu)))
continue;
}
if (CLOAK(user) && (user != cu) && !CHATSYSOP(cu)) /* Thor:隱身朮 */
continue;
#ifdef HAVE_KILL_GAME
if (whichroom != ROOM_ALL && whichroom->rflag & (ROOM_KILLGAME | ROOM_KILL_STARTED))
sprintf(buf + (c * 24), " %-8s%c%-12s%s",
user->chatid, ROOMOP(user) ? '*' : ' ',
userkillstates[kill_get_user_state(whichroom,cu,user)], (c < 2 ? "│" : " "));
else
sprintf(buf + (c * 24), " %-8s%c%-12s%s",
user->chatid, ROOMOP(user) ? '*' : ' ',
user->userid, (c < 2 ? "│" : " "));
#else
sprintf(buf + (c * 24), " %-8s%c%-12s%s",
user->chatid, ROOMOP(user) ? '*' : ' ',
user->userid, (c < 2 ? "│" : " "));
#endif
if (++c == 3)
{
send_to_user(cu, buf, 0, MSG_MESSAGE);
c = 0;
}
}
if (c > 0)
send_to_user(cu, buf, 0, MSG_MESSAGE);
}
static void
chat_map_chatids_thisroom(cu, msg)
ChatUser *cu;
char *msg;
{
chat_map_chatids(cu, cu->room);
}
static void
chat_setroom(cu, msg)
ChatUser *cu;
char *msg;
{
char *modestr;
ChatRoom *room;
char *chatid;
int sign, flag;
char *fstr, buf[128];
if (!ROOMOP(cu))
{
send_to_user(cu, msg_not_op, 0, MSG_MESSAGE);
return;
}
modestr = nextword(&msg);
sign = 1;
if (*modestr == '+')
{
modestr++;
}
else if (*modestr == '-')
{
modestr++;
sign = 0;
}
if (*modestr == '\0')
{
send_to_user(cu,
"※ 請指定狀態: {[+(設定)][-(取消)]}{[L(鎖住)][s(秘密)][t(開放話題)}", 0,
MSG_MESSAGE);
return;
}
room = cu->room;
chatid = cu->chatid;
while (*modestr)
{
flag = 0;
switch (*modestr)
{
case 'l':
case 'L':
flag = ROOM_LOCKED;
fstr = "鎖住";
break;
case 's':
case 'S':
flag = ROOM_SECRET;
fstr = "秘密";
break;
case 't':
case 'T':
flag = ROOM_OPENTOPIC;
fstr = "開放話題";
break;
/* fuse.991210: 清靜聊天室 */
case 'q':
case 'Q':
flag = ROOM_QUIET;
fstr = "清靜聊天室";
break;
case 'i':
case 'I':
flag = ROOM_INTERVIEW;
fstr = "貴賓專訪";
break;
default:
sprintf(buf, "※ 狀態錯誤:[%c]", *modestr);
send_to_user(cu, buf, 0, MSG_MESSAGE);
}
/* Thor: check room 是不是空的, 應該不是空的 */
if (flag && (room->rflag & flag) != sign * flag)
{
room->rflag ^= flag;
if (!CLOAK(cu))
{
sprintf(buf, "※ 本聊天室被 %s %s [%s] 狀態",
chatid, sign ? "設定為" : "取消", fstr);
send_to_room(room, buf, 0, MSG_MESSAGE,NULL);
}
}
modestr++;
}
/* Thor.980602: 不准 Main room 鎖起 or 秘密, 這成何體統?
離開的就進不來, 要看也看不到?
想要踢人也踢不進 main room, 不會很奇怪嗎? */
if(str_equal(MAIN_NAME, room->name))
{
if(room->rflag & (ROOM_LOCKED | ROOM_SECRET))
{
send_to_room(room, "※ 但 真情使者 施了『復原』的魔法", 0, MSG_MESSAGE,
NULL);
room->rflag &= ~(ROOM_LOCKED|ROOM_SECRET);
}
}
room_changed(room);
}
static char *chat_msg[] =
{
"[//]help", "MUD-like 社交動詞",
"[/h]elp op", "談天室管理員專用指令",
#ifdef HAVE_KILL_GAME
"[/h]elp ki","殺手遊戲專用指令",
#endif
"[/a]ct <msg>", "做一個動作",
"[/b]ye [msg]", "道別",
"[/c]lear [/d]ate", "清除螢幕 目前時間",
/*"[/d]ate", "目前時間", *//* Thor: 指令太多 */
#if 0
"[/f]ire <user> <msg>", "發送熱訊", /* Thor.0727: 和 flag 沖key */
#endif
"[/ignore] [user]", "忽略使用者",
"[/i]nvite [user]", "邀請使用者",
"[/j]oin <room>", "建立或加入談天室",
"[/l]ist [start [stop]]", "列出談天室使用者",
"[/m]sg <id|user> <msg>", "跟 <id> 說悄悄話",
"[/n]ick <id>", "將談天代號換成 <id>",
"[/p]ager", "切換呼叫器",
"[/q]uery <user>", "查詢網友",
"[/r]oom", "列出一般談天室",
"[/t]ape", "開關錄音機",
"[/to] <user>", "對使用者說!",
"[/unignore] <user>", "取消忽略",
#if 0
"[/u]sers", "列出站上使用者",
#endif
"[/w]ho", "列出本談天室使用者",
"[/w]hoin <room>", "列出談天室<room> 的使用者",
NULL
};
static char *room_msg[] =
{
"[/f]lag [+-][lst]", "設定鎖定、秘密、開放話題",
"[/i]nvite <id>", "邀請 <id> 加入談天室",
"[/kick] <id>", "將 <id> 踢出談天室",
"[/o]p [<id>]", "將 Op 的權力轉移給 <id>",
"[/topic] <text>", "換個話題",
"[/w]all", "廣播 (站長專用)",
NULL
};
#ifdef HAVE_KILL_GAME
static char* kill_msg[] =
{
"[/jk]ill <room>", "建立或加入殺手遊戲談天室",
"[/ks]tart ...","開始殺手遊戲(OP專用),參數如下,以空格分隔",
" police","強制出現警察",
" nopolice","強制不出現警察",
" discuss","允許輪流發言時大家插嘴",
" noghost","死人不能隨意發言",
" strpolice","警察每回合發現一個殺手(殺手投票后)",
"[/ke]nd","結束殺手遊戲(OP專用)",
"[/kill] <user>","殺手遊戲中處決一個人,屬于投票性質",
"[/kq]uery]","殺手遊戲中警察查詢一個人的真實身份",
"[/ko]ver]","殺手遊戲中認為自己本輪任務已完成,如查看和發言",
"[/kkk]","殺手遊戲中觸發時間檢查,任何人都可使用,包括死人",
NULL
};
#endif
static void
chat_help(cu, msg)
ChatUser *cu;
char *msg;
{
char **table, *str, buf[128];
if (str_equal("op", nextword(&msg)))
{
send_to_user(cu, "談天室管理員專用指令", 0, MSG_MESSAGE);
table = room_msg;
}
#ifdef HAVE_KILL_GAME
else if (!str_cmp("ki", nextword(&msg)))
{
send_to_user(cu, "殺手遊戲專用指令",0,MSG_MESSAGE);
table = kill_msg;
}
#endif
else
{
table = chat_msg;
}
while (str = *table++)
{
sprintf(buf, " %-20s- %s", str, *table++);
send_to_user(cu, buf, 0, MSG_MESSAGE);
}
}
static void
chat_private(cu, msg)
ChatUser *cu;
char *msg;
{
ChatUser *xuser;
int userno;
char *recipient, buf[128];
userno = 0;
recipient = nextword(&msg);
if (strcmp(recipient, interviewer) == 0)
{
/* 被采訪人不接受訊息 */
if (INTERVIEW(cu->room) && (!(ROOMOP(cu))))
return;
}
xuser = (ChatUser *) fuzzy_cuser_by_chatid(recipient);
if (xuser == NULL) /* Thor.0724: 用 userid也可傳悄悄話 */
{
xuser = cuser_by_userid(recipient);
}
if (xuser == NULL)
{
sprintf(buf, msg_no_such_id, recipient);
}
else if (xuser == FUZZY_USER)
{ /* ambiguous */
strcpy(buf, "※ 請指明聊天代號");
}
else if (*msg)
{
#ifdef HAVE_KILL_GAME
if(cu->room == xuser->room)
{
if(cu->room->rflag & ROOM_KILL_STARTED)
{
if(KILL_ROLE(cu) != KILL_KILLER || KILL_ROLE(xuser) != KILL_KILLER)
{
send_to_user(cu,"\033[1;33m$$ 遊戲中不能說悄悄話!\033[m",
0, MSG_MESSAGE);
return;
}
}
}
#endif
userno = cu->userno;
sprintf(buf, "*%s* ", cu->chatid);
msg[79] = 0; /* Thor:防止太長 */
strncat(buf, msg, 80);
send_to_user(xuser, buf, userno, MSG_MESSAGE);
if (xuser->clitype)
{ /* Xshadow: 如果對方是用 client 上來的 */
sprintf(buf, "%s %s ", cu->userid, cu->chatid);
msg[79] = 0;
strncat(buf, msg, 80);
send_to_user(xuser, buf, userno, MSG_PRIVMSG);
}
if (cu->clitype)
{
sprintf(buf, "%s %s ", xuser->userid, xuser->chatid);
msg[79] = 0;
strncat(buf, msg, 80);
send_to_user(cu, buf, 0, MSG_MYPRIVMSG);
}
sprintf(buf, "%s> ", xuser->chatid);
strncat(buf, msg, 80);
}
else
{
sprintf(buf, "※ 您想對 %s 說什麼話呢?", xuser->chatid);
}
send_to_user(cu, buf, userno, MSG_MESSAGE);
/* Thor: userno 要改成 0 嗎? */
}
static void
chat_cloak(cu, msg)
ChatUser *cu;
char *msg;
{
if (CHATSYSOP(cu))
{
char buf[128];
cu->uflag ^= PERM_CLOAK;
sprintf(buf, "◆ %s", CLOAK(cu) ? MSG_CLOAKED : MSG_UNCLOAK);
send_to_user(cu, buf, 0, MSG_MESSAGE);
}
}
/* ----------------------------------------------------- */
static void
arrive_room(cuser, room)
ChatUser *cuser;
ChatRoom *room;
{
char *rname, buf[1024];
/* Xshadow: 不必送給自己, 反正換房間就會重新 build user list */
sprintf(buf, "+ %s %s %s %s",
cuser->userid, cuser->chatid, room->name, cuser->rhost);
if (ROOMOP(cuser))
strcat(buf, " Op");
send_to_room(room, buf, 0, MSG_USERNOTIFY,NULL);
room->occupants++;
room_changed(room);
cuser->room = room;
rname = room->name;
if (cuser->clitype)
{
send_to_user(cuser, rname, 0, MSG_ROOM);
send_to_user(cuser, room->topic, 0, MSG_TOPIC);
}
else
{
sprintf(buf, "/r%s", rname);
send_to_user(cuser, buf, 0, MSG_MESSAGE);
sprintf(buf, "/t%s", room->topic);
send_to_user(cuser, buf, 0, MSG_MESSAGE);
#ifdef HAVE_KILL_GAME
if(room->rflag & ROOM_KILLGAME)
{
sprintf(buf,"/k6");
send_to_user(cuser, buf, 0, MSG_MESSAGE);
sprintf(buf,"/u5 %s",MSG_SEPERATOR);
send_to_user(cuser, buf, 0, MSG_MESSAGE);
}
else
{
sprintf(buf,"/k2");
send_to_user(cuser,buf,0,MSG_MESSAGE);
}
#endif
}
/* fuse.991210: INTERVIEW模式下進入不顯示了 */
if (!INTERVIEW(cuser->room))
sprintf(buf, "※ %s 進入 [%s] 包廂",
cuser->chatid, rname);
if (!CLOAK(cuser))
send_to_room(room, buf, cuser->userno, MSG_MESSAGE,NULL);
else
send_to_user(cuser, buf, 0, MSG_MESSAGE);
}
static int
enter_room(cuser, rname, msg, crflag)
ChatUser *cuser;
char *rname;
char *msg;
int crflag;
{
ChatRoom *room;
int create;
char buf[256];
create = 0;
room = croom_by_roomid(rname);
if (room == NULL)
{
/* new room */
#ifdef DEBUG
logit(cuser->userid, "create new room");
debug_room();
#endif
if (room = roompool)
{
roompool = room->next;
}
else
{
room = (ChatRoom *) malloc(sizeof(ChatRoom));
}
if (room == NULL)
{
send_to_user(cuser, "※ 無法再新辟包廂了", 0, MSG_MESSAGE);
return 0;
}
memset(room, 0, sizeof(ChatRoom));
/* str_ncpy(room->name, rname, IDLEN - 1); */
str_ncpy(room->name, rname, IDLEN);
/* Thor.980921: 已包含 0 */
strcpy(room->topic, "這是一個新天地");
#ifdef HAVE_KILL_GAME
if(crflag & ROOM_KILLGAME)
{
strcat(room->topic,"K");
room->rflag |= ROOM_KILLGAME;
}
#endif
sprintf(buf, "+ %s 1 0 %s", room->name, room->topic);
send_to_room(ROOM_ALL, buf, 0, MSG_ROOMNOTIFY,NULL);
if (mainroom.next)
mainroom.next->prev = room;
room->next = mainroom.next;
mainroom.next = room;
room->prev = &mainroom;
#ifdef DEBUG
logit(cuser->userid, "create room succeed");
debug_room();
#endif
create = 1;
fprintf(flog, "room+\t[%d] %s\n", cuser->sno, rname);
}
else
{
#ifdef HAVE_KILL_GAME
if(crflag & ROOM_KILLGAME)
{
if(!(room->rflag & ROOM_KILLGAME))
{
send_to_user(cuser,"※ 這個聊天室不是殺手遊戲室",0,MSG_MESSAGE);
return 0;
}
if(room->rflag & ROOM_KILL_STARTED)
{
send_to_user(cuser,"※ 這個聊天室的遊戲已經開始了:(",0,MSG_MESSAGE);
return 0;
}
}
#endif
if (cuser->room == room)
{
sprintf(buf, "※ 您本來就在 [%s] 聊天室囉 :)", rname);
send_to_user(cuser, buf, 0, MSG_MESSAGE);
return 0;
}
#ifdef HAVE_KILL_GAME
if(room->rflag & ROOM_KILLGAME && room->rflag & ROOM_KILL_STARTED)
{
send_to_user(cuser,"※ 這個聊天室裡正在進行遊戲",0,MSG_MESSAGE);
return 0;
}
#endif
if (!CHATSYSOP(cuser) && LOCKED(room) &&
!list_belong(room->invite, cuser->userno))
{
send_to_user(cuser, "※ 內有惡犬,非請莫入", 0, MSG_MESSAGE);
return 0;
}
}
exit_room(cuser, EXIT_LOGOUT, msg);
arrive_room(cuser, room);
if (create)
cuser->uflag |= PERM_ROOMOP;
return 0;
}
static void
cuser_free(cuser)
ChatUser *cuser;
{
int sock;
sock = cuser->sock;
shutdown(sock, 2);
close(sock);
FD_CLR(sock, &mainfset);
list_free(&cuser->ignore);
totaluser--;
if (cuser->room)
{
exit_room(cuser, EXIT_LOSTCONN, NULL);
}
fprintf(flog, "BYE\t[%d] T%d X%d\n",
cuser->sno, time(0) - cuser->tbegin, cuser->xdata);
}
static void
print_user_counts(cuser)
ChatUser *cuser;
{
ChatRoom *room;
int num, userc, suserc, roomc, number;
char buf[256];
userc = suserc = roomc = 0;
room = &mainroom;
do
{
num = room->occupants;
if (SECRET(room))
{
suserc += num;
if (CHATSYSOP(cuser))
roomc++;
}
else
{
userc += num;
roomc++;
}
} while (room = room->next);
number = (cuser->clitype) ? MSG_MOTD : MSG_MESSAGE;
sprintf(buf,
"⊙ 歡迎光臨【真情聊天室】,目前開了 %d 間包廂", roomc);
send_to_user(cuser, buf, 0, number);
sprintf(buf, "⊙ 共有 %d 人來擺龍門陣", userc);
if (suserc)
sprintf(buf + strlen(buf), " [%d 人在秘密聊天室]", suserc);
send_to_user(cuser, buf, 0, number);
}
static int
login_user(cu, msg)
ChatUser *cu;
char *msg;
{
int utent;
char *userid;
char *chatid, *passwd;
ChatUser *xuser;
int level;
/* struct hostent *hp; */
#ifndef STAND_ALONE
ACCT acct;
#endif
/* Xshadow.0915: common client support : /-! userid chatid password */
/* client/server 版本依據 userid 抓 .PASSWDS 判斷 userlevel */
userid = nextword(&msg);
chatid = nextword(&msg);
#ifdef DEBUG
logit("ENTER", userid);
#endif
#ifndef STAND_ALONE
/* Thor.0730: parse space before passwd */
passwd = msg;
/* Thor.0813: 跳過一空格即可, 因為反正如果chatid有空格, 密碼也不對 */
/* 就算密碼對, 也不會怎麼樣:p */
/* 可是如果密碼第一個字是空格, 那跳太多空格會進不來... */
/* Thor.980910: 由於 nextword修改為後接空格填0, 傳入值則直接後移至0後,
所以不需作此動作 */
#if 0
if (*passwd == ' ')
passwd++;
#endif
/* Thor.0729: load acct */
if (!*userid || (acct_load(&acct, userid) < 0))
{
#ifdef DEBUG
logit("noexist", userid);
#endif
if (cu->clitype)
send_to_user(cu, "錯誤的使用者代號", 0, ERR_LOGIN_NOSUCHUSER);
else
send_to_user(cu, CHAT_LOGIN_INVALID, 0, MSG_MESSAGE);
return -1;
}
/* Thor.0813: 改用真實 password check, for C/S bbs */
/* Thor.990214: 注意,daolib中 非0代表失敗 */
/* if (!chkpasswd(acct.passwd, passwd)) */
if (chkpasswd(acct.passwd, passwd))
{
#ifdef DEBUG
logit("fake", userid);
#endif
if (cu->clitype)
send_to_user(cu, "密碼錯誤", 0, ERR_LOGIN_PASSERROR);
else
send_to_user(cu, CHAT_LOGIN_INVALID, 0, MSG_MESSAGE);
return -1;
}
level = acct.userlevel;
utent = acct.userno;
#else /* STAND_ALONE */
level = 1;
utent = ++userno_inc;
#endif /* STAND_ALONE */
/* Thor.0819: for client/server bbs */
#ifdef DEBUG
log_user(NULL);
#endif
for (xuser = mainuser; xuser; xuser = xuser->unext)
{
#ifdef DEBUG
log_user(xuser);
#endif
if (xuser->userno == utent)
{
#ifdef DEBUG
logit("enter", "bogus");
#endif
#ifdef HAVE_KILL_GAME
if(xuser->killflag &= KILL_DROPED)
{
char buf[128];
xuser->sock = cu->sock;
xuser->clitype = cu->clitype;
totaluser --;
cu->unext = userpool;
userpool = cu;
xuser->room->occupants ++;
sprintf(buf,"\033[1;33m$$ $$ 歡迎 %s 回來繼續遊戲 $$ $$",xuser->chatid)
;
send_to_room(xuser->room,buf,0,MSG_MESSAGE,NULL);
xuser->killflag &= ~KILL_DROPED;
kill_on_reconnect(xuser->room);
}
else
{
if (cu->clitype)
send_to_user(cu, "請勿派遣分身進入聊天室 !!", 0,
ERR_LOGIN_USERONLINE);
else
send_to_user(cu, CHAT_LOGIN_BOGUS, 0, MSG_MESSAGE);
return -1; /* Thor: 或是0等它自己了斷? */
}
#else
if (cu->clitype)
send_to_user(cu, "請勿派遣分身進入聊天室 !!", 0,
ERR_LOGIN_USERONLINE);
else
send_to_user(cu, CHAT_LOGIN_BOGUS, 0, MSG_MESSAGE);
return -1; /* Thor: 或是0等它自己了斷? */
#endif
}
}
#ifndef STAND_ALONE
/* Thor.980629: 暫時借用 invalid_chatid 濾除 沒有PERM_CHAT的人 */
if (!valid_chatid(chatid) || !(level & PERM_CHAT) || (level & PERM_DENYCHAT))
{ /* Thor.981012: 徹底一些, 連 denychat也BAN掉, 免得 client作怪 */
#ifdef DEBUG
logit("enter", chatid);
#endif
if (cu->clitype)
send_to_user(cu, "不合法的聊天室代號 !!", 0, ERR_LOGIN_NICKERROR);
else
send_to_user(cu, CHAT_LOGIN_INVALID, 0, MSG_MESSAGE);
return 0;
}
#endif
#ifdef DEBUG
debug_user();
#endif
if (cuser_by_chatid(chatid) != NULL)
{
/* chatid in use */
#ifdef DEBUG
logit("enter", "duplicate");
#endif
if (cu->clitype)
send_to_user(cu, "這個代號已經有人使用", 0, ERR_LOGIN_NICKINUSE);
else
send_to_user(cu, CHAT_LOGIN_EXISTS, 0, MSG_MESSAGE);
return 0;
}
#ifdef DEBUG /* CHATSYSOP 一進來就隱身 */
cu->uflag = level & ~(PERM_ROOMOP | PERM_CHATOP | (CHATSYSOP(cu) ? 0 : PERM_C
LOAK));
#else
cu->uflag = level & ~(PERM_ROOMOP | PERM_CHATOP | PERM_CLOAK);
#endif
/* Thor: 進來先清空 ROOMOP (同PERM_CHAT) */
strcpy(cu->userid, userid);
str_ncpy(cu->chatid, chatid, sizeof(cu->chatid));
/* Thor.980921: str_ncpy與一般 strncpy有所不同, 特別注意 */
/* Thor.980921: 防止太長 */
/* cu->chatid[8]=0; */
fprintf(flog, "ENTER\t[%d] %s\n", cu->sno, userid);
/* Xshadow: 取得 client 的來源 */
dns_name(cu->rhost, cu->ibuf);
str_ncpy(cu->rhost, cu->ibuf, sizeof(cu->rhost));
#if 0
hp = gethostbyaddr(cu->rhost, sizeof(struct in_addr), AF_INET);
str_ncpy(cu->rhost,
hp ? hp->h_name : inet_ntoa((struct in_addr *) cu->rhost),
sizeof(cu->rhost) - 1);
#endif
cu->userno = utent;
if (cu->clitype)
send_to_user(cu, "順利", 0, MSG_LOGINOK);
else
send_to_user(cu, CHAT_LOGIN_OK, 0, MSG_MESSAGE);
arrive_room(cu, &mainroom);
send_to_user(cu, "", 0, MSG_MOTDSTART);
print_user_counts(cu);
send_to_user(cu, "", 0, MSG_MOTDEND);
#ifdef DEBUG
logit("enter", "OK");
#endif
return 0;
}
static void
chat_act(cu, msg)
ChatUser *cu;
char *msg;
{
if (QUIET(cu->room) && (!(ROOMOP(cu))))
return;
#ifdef HAVE_KILL_GAME
if(!kill_can_talk(cu->room,cu))
{
send_to_user(cu,"\033[1;35m$$ 你現在做的動作別人看不到哦\033[m",
0, MSG_MESSAGE);
return;
}
#endif
if (*msg)
{
char buf[256];
sprintf(buf, "%s %s", cu->chatid, msg);
send_to_room(cu->room, buf, cu->userno, MSG_MESSAGE,cu);
}
}
static void
chat_ignore(cu, msg)
ChatUser *cu;
char *msg;
{
char *str, buf[256];
if (RESTRICTED(cu))
{
str = "※ 您沒有 ignore 別人的權利";
}
else
{
char *ignoree;
str = buf;
ignoree = nextword(&msg);
if (*ignoree)
{
ChatUser *xuser;
xuser = cuser_by_userid(ignoree);
if (xuser == NULL)
{
sprintf(str, msg_no_such_id, ignoree);
}
else if (xuser == cu || CHATSYSOP(xuser) ||
(ROOMOP(xuser) && (xuser->room == cu->room)))
{
sprintf(str, "◆ 不可以 ignore [%s]", ignoree);
}
else
{
if (list_belong(cu->ignore, xuser->userno))
{
sprintf(str, "※ %s 已經被凍結了", xuser->chatid);
}
else
{
list_add(&(cu->ignore), xuser);
sprintf(str, "◆ 將 [%s] 打入冷宮了 :p", xuser->chatid);
}
}
}
else
{
UserList *list;
if (list = cu->ignore)
{
int len;
char userid[16];
send_to_user(cu, "◆ 這些人被打入冷宮了:", 0, MSG_MESSAGE);
len = 0;
do
{
sprintf(userid, "%-13s", list->userid);
strcpy(str + len, userid);
len += 13;
if (len >= 78)
{
send_to_user(cu, str, 0, MSG_MESSAGE);
len = 0;
}
} while (list = list->next);
if (len == 0)
return;
}
else
{
str = "◆ 您目前并沒有 ignore 任何人";
}
}
}
send_to_user(cu, str, 0, MSG_MESSAGE);
}
static void
chat_unignore(cu, msg)
ChatUser *cu;
char *msg;
{
char *ignoree, *str, buf[80];
ignoree = nextword(&msg);
if (*ignoree)
{
sprintf(str = buf, (list_delete(&(cu->ignore), ignoree)) ?
"◆ [%s] 不再被你冷落了" :
"◆ 您并未 ignore [%s] 這號人物", ignoree);
}
else
{
str = "◆ 請指明 user ID";
}
send_to_user(cu, str, 0, MSG_MESSAGE);
}
static void
chat_join(cu, msg)
ChatUser *cu;
char *msg;
{
if (RESTRICTED(cu))
{
send_to_user(cu, "※ 您沒有加入其他聊天室的權限", 0, MSG_MESSAGE);
}
else
{
char *roomid = nextword(&msg);
if (*roomid)
enter_room(cu, roomid, msg, 0);
else
send_to_user(cu, "※ 請指定聊天室", 0, MSG_MESSAGE);
}
}
#ifdef HAVE_KILL_GAME
static void
kill_join(cu, msg)
ChatUser *cu;
char *msg;
{
if (RESTRICTED(cu))
{
send_to_user(cu, "※ 您沒有加入其他聊天室的權限", 0, MSG_MESSAGE);
}
else
{
char *roomid = nextword(&msg);
if (*roomid)
enter_room(cu, roomid, msg, ROOM_KILLGAME);
else
send_to_user(cu, "※ 請指定聊天室", 0, MSG_MESSAGE);
}
}
#endif
static void
chat_interview(cu, msg)
ChatUser *cu;
char *msg;
{
char *twit, buf[80];
ChatUser *xuser;
if (!ROOMOP(cu))
{
send_to_user(cu, msg_not_op, 0, MSG_MESSAGE);
return;
}
twit = nextword(&msg);
xuser = cuser_by_chatid(twit);
if (xuser == NULL)
{ /* Thor.980604: 用 userid也嘛通 */
xuser = cuser_by_userid(twit);
}
if (xuser == NULL)
{
sprintf(buf, msg_no_such_id, twit);
send_to_user(cu, buf, 0, MSG_MESSAGE);
return;
}
strcpy(interviewer, twit);
}
static void
chat_kick(cu, msg)
ChatUser *cu;
char *msg;
{
char *twit, buf[80];
ChatUser *xuser;
ChatRoom *room;
if (!ROOMOP(cu))
{
send_to_user(cu, msg_not_op, 0, MSG_MESSAGE);
return;
}
twit = nextword(&msg);
xuser = cuser_by_chatid(twit);
if (xuser == NULL)
{ /* Thor.980604: 用 userid也嘛通 */
xuser = cuser_by_userid(twit);
}
if (xuser == NULL)
{
sprintf(buf, msg_no_such_id, twit);
send_to_user(cu, buf, 0, MSG_MESSAGE);
return;
}
room = cu->room;
if (room != xuser->room || CLOAK(xuser))
{
sprintf(buf, msg_not_here, twit);
send_to_user(cu, buf, 0, MSG_MESSAGE);
return;
}
if (CHATSYSOP(xuser))
{
sprintf(buf, "◆ 不可以 kick [%s]", twit);
send_to_user(cu, buf, 0, MSG_MESSAGE);
return;
}
exit_room(xuser, EXIT_KICK, (char *) NULL);
if (room == &mainroom)
xuser->uptime = 0; /* logout_user(xuser); */
else
enter_room(xuser, MAIN_NAME, (char *) NULL, 0);
/* Thor.980602: 其實踢就踢,不要show出xxx離開了的訊息比較好 */
}
static void
chat_makeop(cu, msg)
ChatUser *cu;
char *msg;
{
char *newop, buf[80];
ChatUser *xuser;
ChatRoom *room;
/* Thor.980603: PERM_CHATROOM改為 default 沒有 roomop, 但可以自己取得 */
newop = nextword(&msg);
room = cu->room;
if(!*newop && CHATSYSOP(cu))
{
/* Thor.980603: PERM_CHATROOM改為 default 沒有 roomop, 但可以自己取得 */
cu->uflag ^= PERM_CHATOP;
user_changed(cu);
if (!CLOAK(cu))
{
sprintf(buf,ROOMOP(cu) ? "※ 真情使者 將 Op 權力授予 %s"
: "※ 真情使者 將 %s 的 Op 權力收回", cu->chatid);
send_to_room(room, buf, 0, MSG_MESSAGE,NULL);
}
return;
}
/* if (!ROOMOP(cu)) */
/* Thor.980603: chat room總管不能轉移 Op 權力 */
/* fuse:我試試說
if (!(cu->uflag & PERM_ROOMOP))
*/
if (!ROOMOP(cu))
{
send_to_user(cu, "◆ 您不能轉移 Op 的權力", 0, MSG_MESSAGE);
return;
}
xuser = cuser_by_chatid(newop);
if (xuser == NULL)
{
sprintf(buf, msg_no_such_id, newop);
send_to_user(cu, buf, 0, MSG_MESSAGE);
return;
}
if (cu == xuser)
{
send_to_user(cu, "※ 您早就已經是 Op 了啊", 0, MSG_MESSAGE);
return;
}
/* room = cu->room; */
if (room != xuser->room || CLOAK(xuser))
{
sprintf(buf, msg_not_here, xuser->chatid);
send_to_user(cu, buf, 0, MSG_MESSAGE);
return;
}
/* 兩次授予Op取消 */
if (CHATSYSOP(cu) && (xuser->uflag & PERM_ROOMOP))
{
xuser->uflag &= ~PERM_ROOMOP;
user_changed(xuser);
return;
}
/* fuse: 如果是chat sysop,那就不把自己權力去掉了 */
if (!CHATSYSOP(cu))
cu->uflag &= ~PERM_ROOMOP;
xuser->uflag |= PERM_ROOMOP;
user_changed(cu);
user_changed(xuser);
if (!CLOAK(cu))
{
sprintf(buf, "※ %s 將 Op 權力轉移給 %s",
cu->chatid, xuser->chatid);
send_to_room(room, buf, 0, MSG_MESSAGE,NULL);
}
}
#if 0
static void
chat_makeop(cu, msg)
ChatUser *cu;
char *msg;
{
char *newop, buf[80];
ChatUser *xuser;
ChatRoom *room;
/* Thor.980603: PERM_CHATROOM改為 default 沒有 roomop, 但可以自己取得 */
if (!ROOMOP(cu))
/* if (!ROOMOP(cu) && !CHATSYSOP(cu)) */
{
send_to_user(cu, msg_not_op, 0, MSG_MESSAGE);
return;
}
newop = nextword(&msg);
xuser = cuser_by_chatid(newop);
#if 0
if (xuser == NULL)
{ /* Thor.980604: 用 userid也嘛通 */
xuser = cuser_by_userid(newop);
}
#endif
if (xuser == NULL)
{
sprintf(buf, msg_no_such_id, newop);
send_to_user(cu, buf, 0, MSG_MESSAGE);
return;
}
if (cu == xuser)
{
send_to_user(cu, "※ 您早就已經是 Op 了啊", 0, MSG_MESSAGE);
return;
}
room = cu->room;
if (room != xuser->room || CLOAK(xuser))
{
sprintf(buf, msg_not_here, xuser->chatid);
send_to_user(cu, buf, 0, MSG_MESSAGE);
return;
}
cu->uflag &= ~PERM_ROOMOP;
xuser->uflag |= PERM_ROOMOP;
user_changed(cu);
user_changed(xuser);
if (!CLOAK(cu))
{
sprintf(buf, "※ %s 將 Op 權力轉移給 %s",
cu->chatid, xuser->chatid);
send_to_room(room, buf, 0, MSG_MESSAGE,NULL);
}
}
#endif
static void
chat_invite(cu, msg)
ChatUser *cu;
char *msg;
{
char *invitee, buf[80];
ChatUser *xuser;
ChatRoom *room;
UserList **list;
if (!ROOMOP(cu))
{
send_to_user(cu, msg_not_op, 0, MSG_MESSAGE);
return;
}
invitee = nextword(&msg);
xuser = cuser_by_chatid(invitee);
#if 0
if (xuser == NULL)
{ /* Thor.980604: 用 userid也嘛通 */
xuser = cuser_by_userid(invitee);
}
#endif
if (xuser == NULL)
{
sprintf(buf, msg_no_such_id, invitee);
send_to_user(cu, buf, 0, MSG_MESSAGE);
return;
}
room = cu->room; /* Thor: 是否要 check room 是否 NULL ? */
list = &(room->invite);
if (list_belong(*list, xuser->userno))
{
sprintf(buf, "※ %s 已經接受過邀請了", xuser->chatid);
send_to_user(cu, buf, 0, MSG_MESSAGE);
return;
}
list_add(list, xuser);
sprintf(buf, "※ %s 邀請您到 [%s] 聊天室",
cu->chatid, room->name);
send_to_user(xuser, buf, 0, MSG_MESSAGE);
sprintf(buf, "※ %s 收到您的邀請了", xuser->chatid);
send_to_user(cu, buf, 0, MSG_MESSAGE);
}
static void
chat_broadcast(cu, msg)
ChatUser *cu;
char *msg;
{
char buf[80];
if (!CHATSYSOP(cu))
{
send_to_user(cu, "※ 您沒有在聊天室廣播的權力!", 0, MSG_MESSAGE);
return;
}
if (*msg == '\0')
{
send_to_user(cu, "※ 請指定廣播內容", 0, MSG_MESSAGE);
return;
}
sprintf(buf, "※ " BOARDNAME "談天室廣播中 [%s].....",
cu->chatid);
send_to_room(ROOM_ALL, buf, 0, MSG_MESSAGE,NULL);
sprintf(buf, "◆ %s", msg);
send_to_room(ROOM_ALL, buf, 0, MSG_MESSAGE,NULL);
}
static void
chat_bye(cu, msg)
ChatUser *cu;
char *msg;
{
exit_room(cu, EXIT_LOGOUT, msg);
cu->uptime = 0;
/* logout_user(cu); */
}
/* --------------------------------------------- */
/* MUD-like social commands : action */
/* --------------------------------------------- */
struct ChatAction
{
char *verb; /* 動詞 */
char *chinese; /* 中文翻譯 */
char *part1_msg; /* 介詞 */
char *part2_msg; /* 動作 */
};
static ChatAction party_data[] =
{
{
"aluba", "阿魯巴", "把", "架上柱子阿魯巴!!"
},
{
"aodre", "景仰", "對", "的景仰有如滔滔江水,連綿不絕……"
},
{
"bearhug", "熱擁", "熱情的擁抱", ""
},
{
"blade", "一刀", "一刀啟程把", "送上西天"
}, /* Thor.0729:觀眾要求 */
{
"bless", "祝福", "祝福", "心想事成"
},
{
"board", "主機板", "把", "抓去跪主機板"
}, /* Thor.0730: 觀眾要求 */
{
"bokan", "氣功", "雙掌微合,蓄勢待發……突然間,電光乍現,對", "使出了Bo--
Kan!"
},
{
"bow", "鞠躬", "畢躬畢敬的向", "鞠躬"
},
{
"box", "幕之內", "開始輪擺式移位,對", "作肝臟攻擊"
},
{
"boy", "平底鍋", "從背後拿出了平底鍋,把", "敲昏了"
},
{
"bye", "掰掰", "向", "說掰掰!!"
},
{
"call", "呼喚", "大聲的呼喚,啊~~", "啊~~~你在哪裡啊啊啊啊~~~~"
},
{
"caress", "輕撫", "輕輕的撫摸著", ""
},
{
"clap", "鼓掌", "向", "熱烈鼓掌"
},
{
"claw", "抓抓", "從貓咪樂園借了只貓爪,把", "抓得死去活來"
},
{
"comfort", "安慰", "溫言安慰", ""
},
{
"cong", "恭喜", "從背後拿出了拉炮,□!□!恭喜", ""
},
{
"cpr", "口對口", "對著", "做口對口人工呼吸"
},
{
"cringe", "乞憐", "向", "卑躬屈膝,搖尾乞憐"
},
{
"cry", "大哭", "向", "嚎啕大哭"
},
{
"dance", "跳舞", "拉了", "的手翩翩起舞"
},
{
"destroy", "毀滅", "祭起了『極大毀滅咒文』,轟向", ""
},
{
"dogleg", "狗腿", "對", "狗腿"
},
{
"drivel", "流口水", "對著", "流口水"
},
#if 0
/* Thor.0729: 與 //love 重覆 */
{
"emotion", "告白", "對", "純情的告白"
},
#endif
{
"envy", "羨慕", "向", "流露出羨慕的眼光"
},
{
"eye", "送秋波", "對", "頻送秋波"
},
{
"fire", "銬問", "拿著火紅的鐵棒走向", ""
},
{
"forgive", "原諒", "接受道歉,原諒了", ""
},
{
"french", "法式吻", "把舌頭伸到", "喉嚨裡~~~哇!一個浪漫的法國氏深吻"
},
{
"giggle", "傻笑", "對著", "傻傻的呆笑"
},
{
"glue", "補心", "用三秒膠,把", "的心黏了起來"
}, /* Thor.0731:應觀眾要求 */
{
"goodbye", "告別", "淚眼汪汪的向", "告別"
},
{
"grin", "奸笑", "對", "露出邪惡的笑容"
},
{
"growl", "咆哮", "對", "咆哮不已"
},
{
"hand", "握手", "跟", "握手"
},
/* {"hide","躲","用力地躲著",""}, */
{
"hide", "躲", "躲在", "背後"
}, /* Thor.0729: 觀眾修改版 */
{
"hospitl", "送醫院", "把", "送進醫院"
},
{
"hug", "擁抱", "輕輕地擁抱", ""
},
{
"hrk", "□龍拳", "沉穩了身形,匯聚了內勁,對", "使出了一記Ho--Ryu--Kan!
!!"
},
{
"hypnoze", "催眠", "拿著挂表晃呀晃的,對", "展開催眠……"
}, /* Thor.980619: 新詞 */
{
"jab", "戳人", "溫柔的戳著", ""
},
{
"judo", "過肩摔", "抓住了", "的衣襟,轉身……啊,是一記過肩摔!"
},
{
"kickout", "踢", "用大腳把", "踢到山下去了"
},
{
"kick", "踢人", "把", "踢的死去活來"
},
{
"kiss", "輕吻", "輕吻", "的臉頰"
},
{
"laugh", "嘲笑", "大聲嘲笑", ""
},
{
"levis", "給我", "說:給我", "!其余免談!"
},
{
"lick", "舔", "狂舔", ""
},
{
"lobster", "壓制", "施展逆蝦形固定,把", "壓制在地板上"
},
{
"love", "表白", "對", "深情的表白"
},
{
"marry", "求婚", "捧著九百九十九朵玫瑰向", "求婚"
},
{
"no", "不要啊", "拼命對著", "搖頭~~~~不要啊~~~~"
},
{
"nod", "點頭", "向", "點頭稱是"
},
{
"nudge", "頂肚子", "用手肘頂", "的肥肚子"
},
{
"pad", "拍肩膀", "輕拍", "的肩膀"
},
{
"pettish", "撒嬌", "跟", "嗲聲嗲氣地撒嬌"
},
{
"pili", "霹靂", "使出 君子風 天地根 般若懺 三式合一打向", "~~~~~~"
},
/* Thor.0729: 應觀眾要求 */
{
"pinch", "擰人", "用力的把", "擰的黑青"
},
{
"roll", "打滾", "放出多爾袞的音樂,", "在地上滾來滾去"
},
{
"protect", "保護", "保護著", ""
},
{
"pull", "拉", "死命地拉住", "不放"
},
{
"punch", "揍人", "狠狠揍了", "一頓"
},
{
"rascal", "耍賴", "跟", "耍賴"
},
{
"recline", "入懷", "鑽到", "的懷裡睡著了……"
},
{
"respond", "負責", "安慰", "說:『不要哭,我會負責的……』"
},
{
"shrug", "聳肩", "無奈地向", "聳了聳肩膀"
},
{
"sigh", "嘆氣", "對", "嘆了一口氣"
},
{
"slap", "打耳光", "啪啪的巴了", "一頓耳光"
},
{
"smooch", "擁吻", "擁吻著", ""
},
{
"snicker", "竊笑", "嘿嘿嘿..的對", "竊笑"
},
{
"sniff", "不屑", "對", "嗤之以鼻"
},
{
"spank", "打屁屁", "用巴掌打", "的臀部"
},
/* {"spank", "用貓爪抓", "的臀部","抓臀部"}, */
{
"squeeze", "緊擁", "緊緊地擁抱著", ""
},
{
"sysop", "召喚", "叫出了踢米熊,把", "踩扁了!"
},
{
"thank", "感謝", "向", "感謝得五體投地"
},
{
"tickle", "搔痒", "咕嘰!咕嘰!搔", "的痒"
},
{
"wake", "搖醒", "輕輕地把", "搖醒"
},
{
"wave", "揮手", "對著", "拼命的搖手"
},
{
"welcome", "歡迎", "歡迎", "進來八卦一下"
},
{
"what", "什麼", "說:『", "哩公瞎密哇隴聽某???□?』"
},
{
"whip", "鞭子", "手上拿著蠟燭,用鞭子痛打", ""
},
{
"wink", "眨眼", "對", "神秘的眨眨眼睛"
},
{
"zap", "猛攻", "對", "瘋狂的攻擊"
},
/* lkchu.981201: add by mat */
{
"1", "1號", "拿出電鋸,朝", "鋸了下去..."
},
{
"2", "2號", "對", "開槍!"
},
{
"3", "3號", "碰了一聲,", "啊~~了一聲!"
},
{
"4", "4號", "挺起機槍,把", "打成蜂窩"
},
{
"5", "5號", "駕著卡車,然後突然對", "右轉..."
},
{
"6", "6號", "bon quey 了!拿起六號沖向", ""
},
{
"7", "7號", "對", "拋了一個媚眼,把他看死了..."
},
{
"8", "8號", "按了 pause,然後開始對", "破口大罵"
},
{
"bite", "咬", "把", "咬得死去活來"
},
{
"bfydown", "防御降", "施展咒語", "防御力下降了..."
},
{
"bfyup", "防御升","施展咒語", "防御力上升了..."
},
{
"clock", "切鬧鐘", "切掉", "的鬧鐘..."
},
{
"cola", "灌可樂", "對", "灌了一桶可樂"
},
{
"cowhide", "鞭打","拿鞭子對", "狠狠地抽打"
},
{
"crime", "道德", "說:", "的道德指數不夠"
},
{
"evening", "晚安", "對", "說『晚安』"
},
{
"fireball", "發火球", "對", "發了一顆火球"
},
{
"hpup", "hp上升", "施展咒語", "生命力上升至極限"
},
{
"kissbye", "吻別", "跟", "吻別..."
},
{
"mail", "打包", "把", "打包遞送到百慕大"
},
{
"morning", "早安", "對", "說『早安』"
},
{
"noon", "午安", "對", "說『午安』"
},
{
"puding", "灌布丁", "對", "灌了一卡車布丁"
},
{
"recycle", "回收桶", "把", "丟到資源回收桶"
},
{
"sex", "騷擾", "對", "騷擾"
},
{
"shit", "雪特", "對", "罵了一聲 雪特"
},
{
"wait", "等一下", "叫", "等一下哦!"
},
{
"wall", "他撞牆", "抓著", "的頭往牆用力撞了几下"
},
{
"blink", "委曲淚", "對著", "眨眨眼,掉下了委曲的眼淚。"
},
{
"book", "丟書", "拿了一本書朝", "那丟了過去"
},
{
"crash", "塊石頭", "使勁地舉起大石頭往", "身上丟去"
},
{
"curtsey", "中古禮", "優雅地對著","行中古世紀的屈膝禮。"
},
{
"fuzzy","飛鳥","派出飛鳥一號向","沖過去"
},
{
"gag","縫嘴巴","把","的嘴巴用針縫起來"
},
{
"glare", "瞪人", "冷冷地瞪著",""
},
{
"kill", "砍人", "把", "亂刀砍死~~~~"
},
{
"listen", "聽", "叫", "閉嘴仔細聽"
},
{
"mglint", "調皮", "眼睛對著", "閃動著一陣調皮的光芒"
},
{
"pat", "拍頭", "拍拍", "的頭"
},
{
"pettish", "撒嬌", "跟", "嗲聲嗲氣地撒嬌"
},
{
"scratch", "磨爪", "撿起", "身邊的石子磨磨自己的利爪"
},
{
"sorry", "對不起", "向", "說對不起! 我錯了!"
},
{
"wiggle", "扭屁股", "對著", "扭屁股"
},
{
NULL, NULL, NULL, NULL
}
};
static int
party_action(cu, cmd, party)
ChatUser *cu;
char *cmd;
char *party;
{
ChatAction *cap;
char *verb, buf[256];
for (cap = party_data; verb = cap->verb; cap++)
{
if (str_equal(verb, cmd))
{
if (*party == '\0')
{
party = "大家";
}
else
{
ChatUser *xuser;
xuser = fuzzy_cuser_by_chatid(party);
if (xuser == NULL)
{ /* Thor.0724: 用 userid也嘛通 */
xuser = cuser_by_userid(party);
}
if (xuser == NULL)
{
sprintf(buf, msg_no_such_id, party);
send_to_user(cu, buf, 0, MSG_MESSAGE);
return 0;
}
else if (xuser == FUZZY_USER)
{
send_to_user(cu, "※ 請指明聊天代號", 0, MSG_MESSAGE);
return 0;
}
else if (cu->room != xuser->room || CLOAK(xuser))
{
sprintf(buf, msg_not_here, party);
send_to_user(cu, buf, 0, MSG_MESSAGE);
return 0;
}
else
{
party = xuser->chatid;
}
}
sprintf(buf, "%s %s %s %s",
cu->chatid, cap->part1_msg, party, cap->part2_msg);
send_to_room(cu->room, buf, cu->userno, MSG_MESSAGE,cu);
return 0; /* Thor: cu->room 是否為 NULL? */
}
}
return 1;
}
/* --------------------------------------------- */
/* MUD-like social commands : speak */
/* --------------------------------------------- */
static ChatAction speak_data[] =
{
{
"ask", "詢問", "問", NULL
},
{
"chant", "歌頌", "高聲歌頌", NULL
},
{
"cheer", "喝采", "喝采", NULL
},
{
"chuckle", "輕笑", "輕笑", NULL
},
{
"curse", "暗幹", "暗幹", NULL
},
/* {"curse", "咒罵", NULL}, */
{
"demand", "要求", "要求", NULL
},
{
"frown", "皺眉頭", "蹙眉", NULL
},
{
"groan", "呻吟", "呻吟", NULL
},
{
"grumble", "發牢騷", "發牢騷", NULL
},
{
"guitar", "彈唱", "邊彈著吉他,邊唱著", NULL
},
/* {"helpme", "呼救","大聲呼救",NULL}, */
{
"hum", "喃喃", "喃喃自語", NULL
},
{
"moan", "怨嘆", "怨嘆", NULL
},
{
"notice", "強調", "強調", NULL
},
{
"order", "命令", "命令", NULL
},
{
"ponder", "沈思", "沈思", NULL
},
{
"pout", "噘嘴", "噘著嘴說", NULL
},
{
"pray", "祈禱", "祈禱", NULL
},
{
"request", "懇求", "懇求", NULL
},
{
"shout", "大罵", "大罵", NULL
},
{
"sing", "唱歌", "唱歌", NULL
},
{
"smile", "微笑", "微笑", NULL
},
{
"smirk", "假笑", "假笑", NULL
},
{
"swear", "發誓", "發誓", NULL
},
{
"tease", "嘲笑", "嘲笑", NULL
},
#if 0
{
"titter", "偷笑", "偷笑", NULL
}, /* Thor.980619: 新詞 */
#endif
{
"whimper", "嗚咽", "嗚咽的說", NULL
},
{
"yawn", "哈欠", "邊打哈欠邊說", NULL
},
{
"yell", "大喊", "大喊", NULL
},
{
NULL, NULL, NULL, NULL
}
};
static int
speak_action(cu, cmd, msg)
ChatUser *cu;
char *cmd;
char *msg;
{
ChatAction *cap;
char *verb, buf[256];
for (cap = speak_data; verb = cap->verb; cap++)
{
if (str_equal(verb, cmd))
{
sprintf(buf, "%s %s: %s",
cu->chatid, cap->part1_msg, msg);
send_to_room(cu->room, buf, cu->userno, MSG_MESSAGE,cu);
return 0;
}
}
return 1;
}
/* ----------------------------------------------------- */
/* MUD-like social commands : condition */
/* ----------------------------------------------------- */
static ChatAction condition_data[] =
{
{
"applaud", "拍手", "啪啪啪啪啪啪啪....", NULL
},
{
"ayo", "唉呦喂", "唉呦喂~~~", NULL
},
{
"back", "坐回來", "回來坐正繼續奮戰", NULL
},
{
"blood", "在血中", "倒在血泊之中", NULL
},
{
"blush", "臉紅", "臉都紅了", NULL
},
{
"broke", "心碎", "的心破碎成一片一片的", NULL
}, /* Thor.0731:應觀眾要求 */
/* {"bokan", "Bo Kan! Bo Kan!", NULL}, */
{
"careles", "沒人理", "嗚~~都沒有人理我 :~~~~", NULL
},
{
"chew", "嗑瓜子", "很悠閑的嗑起瓜子來了", NULL
},
{
"climb", "爬山", "自己慢慢爬上山來……", NULL
},
{
"cold", "感冒了", "感冒了,媽媽不讓我出去玩 :~~~(", NULL
},
{
"cough", "咳嗽", "咳了几聲", NULL
},
{
"die", "暴斃", "當場暴斃", NULL
},
{
"faint", "昏倒", "當場昏倒", NULL
},
{
"flop", "香蕉皮", "踩到香蕉皮... 滑倒!", NULL
},
{
"fly", "飄飄然", "飄飄然", NULL
},
{
"frown", "蹙眉", "蹙眉", NULL
},
{
"gold", "拿金牌", "唱著:『金ㄍㄠ□金ㄍㄠ□ 出國比賽! 得冠軍,拿金牌!』",
NULL
},
{
"gulu", "肚子餓", "的肚子發出咕嚕~~~咕嚕~~~的聲音", NULL
},
{
"haha", "哇哈哈", "哇哈哈哈.....^o^", NULL
},
/* {"haha", "大笑","哇哈哈哈哈哈哈哈哈~~~~!!!!!", NULL}, */
{
"helpme", "求救", "大喊~~~救命啊~~~~", NULL
},
{
"hoho", "呵呵笑", "呵呵呵笑個不停", NULL
},
{
"happy", "高興", "高興得在地上打滾", NULL
},
/* {"happy", "高興", "YA! *^_^*", NULL}, */
/* {"happy", "", "r-o-O-m....聽了真爽!", NULL}, */
/* {"hurricane", "Ho---Ryu--Kan!!!", NULL}, */
{
"hypnzed", "被催眠", "眼神呆滯,被催眠了……zZzzzz", NULL
}, /* Thor.980619: 新詞 */
{
"idle", "呆住了", "呆住了", NULL
},
{
"jacky", "晃晃", "痞子般的晃來晃去", NULL
},
#if 0
/* Thor.0729: 不知其意 */
{
"lag", "網路慢", "lllllllaaaaaaaaaaaagggggggggggggg.................", NULL
},
#endif
{
"luck", "幸運", "哇!福氣啦!", NULL
},
{
"macarn", "一種舞", "開始跳起了MaCaReNa~~~~", NULL
},
{
"miou", "喵喵", "喵喵口苗口苗~~~~~", NULL
},
{
"mouth", "扁嘴", "扁嘴中!!", NULL
},
{
"nani", "怎麼會", ":奈ㄝ啊捏??", NULL
},
{
"nose", "流鼻血", "流鼻血", NULL
},
{
"puke", "嘔吐", "嘔吐中", NULL
},
/* {"puke", "真惡心,我聽了都想吐", NULL}, */
{
"rest", "休息", "休息中,請勿打擾", NULL
},
{
"reverse", "翻肚", "翻肚", NULL
},
{
"room", "開房間", "r-o-O-m-r-O-O-Mmm-rRR........", NULL
},
{
"shake", "搖頭", "搖了搖頭", NULL
},
{
"sleep", "睡著", "趴在鍵盤上睡著了,口水流進鍵盤,造成當機!", NULL
},
{
"so", "就醬子", "就醬子!!", NULL
},
{
"sorry", "道歉", "嗚啊!!我對不起大家,我對不起國家社會~~~~~~嗚啊~~~~~", NULL
},
{
"story", "講古", "開始講古了", NULL
},
{
"strut", "搖擺走", "大搖大擺地走", NULL
},
{
"suicide", "自殺", "自殺", NULL
},
{
"tea", "泡茶", "泡了壺好茶", NULL
},
{
"think", "思考", "歪著頭想了一下", NULL
},
{
"tongue", "吐舌", "吐了吐舌頭", NULL
},
{
"wall", "撞牆", "跑去撞牆", NULL
},
{
"wawa", "哇哇", "哇哇哇~~~~~!!!!! ~~~>_<~~~", NULL
},
{
"www", "汪汪", "汪汪汪!!!", NULL
},
{
"zzz", "打呼", "呼嚕~~~~ZZzZzzZZZzzZzzzZZ...", NULL
},
/* lkchu.981201: add by mat */
{
"agree", "同意", "深表同意", NULL
},
{
"ah", "靈光", "苦思良久,忽然靈光一現,不禁呀的一聲。", NULL
},
{
"ak", "插腰", "又氣又無奈的兩手插腰", NULL
},
{
"avert", "害羞", "害羞地轉開視線", NULL
},
{
"dive", "賺錢", "埋首研究怎樣賺大錢。", NULL
},
{
"hiccup", "打嗝", "打嗝中", NULL
},
{
"jealous", "吃醋", "氣鼓鼓地喝了一缸醋", NULL
},
{
"jump", "跳樓", "跳樓自殺", NULL
},
{
"mutter", "低咕", "低聲咕噥著某些事。", NULL
},
{
"scream", "尖叫", "大聲尖叫!! 啊~~~~~~~", NULL
},
{
"snore", "打鼾中", "打鼾中...", NULL
},
{
"stare", "凝視", "靜靜地凝視著天空", NULL
},
{
"stretch", "疲倦", "伸伸懶腰又打了個呵欠很疲倦似的。", NULL
},
{
"sweat", "流汗", "揮汗如雨!!", NULL
},
{
"tear", "流淚", "痛哭流涕中.....", NULL
},
{
"wc", "洗手間", "企洗手間一下 :>", NULL
},
{
"whine", "肚子餓", "肚子餓! :(", NULL
},
{
"whistle", "吹口哨", "吹口哨", NULL
},
{
"ya", "ㄛ耶", "噢~YA! *^_^*", NULL
},
{
NULL, NULL, NULL, NULL
}
};
static int
condition_action(cu, cmd)
ChatUser *cu;
char *cmd;
{
ChatAction *cap;
char *verb, buf[256];
for (cap = condition_data; verb = cap->verb; cap++)
{
if (str_equal(verb, cmd))
{
sprintf(buf, "%s %s",
cu->chatid, cap->part1_msg);
send_to_room(cu->room, buf, cu->userno, MSG_MESSAGE,cu);
return 1;
}
}
return 0;
}
/* --------------------------------------------- */
/* MUD-like social commands : help */
/* --------------------------------------------- */
static char *dscrb[] =
{
"【 Verb + Nick: 動詞 + 對方名字 】 例://kick piggy",
"【 Verb + Message:動詞 + 要說的話 】 例://sing 天天天藍",
"【 Verb:動詞 】 ↑↓:舊話重提", NULL
};
static ChatAction *catbl[] =
{
party_data, speak_data, condition_data, NULL
};
static void
chat_partyinfo(cu, msg)
ChatUser *cu;
char *msg;
{
if (common_client_command)
{
send_to_user(cu, "3 動作 交談 狀態", 0, MSG_PARTYINFO);
}
}
static void
chat_party(cu, msg)
ChatUser *cu;
char *msg;
{
int kind, i;
ChatAction *cap;
char buf[80];
if (!common_client_command)
return;
kind = atoi(nextword(&msg));
if (kind < 0 || kind > 2)
return;
sprintf(buf, "%d\t%s", kind, kind == 2 ? "I" : "");
/* Xshadow: 只有 condition 才是 immediate mode */
send_to_user(cu, buf, 0, MSG_PARTYLISTSTART);
cap = catbl[kind];
for (i = 0; cap[i].verb; i++)
{
sprintf(buf, "%-10s %-20s", cap[i].verb, cap[i].chinese);
send_to_user(cu, buf, 0, MSG_PARTYLIST);
}
sprintf(buf, "%d", kind);
send_to_user(cu, buf, 0, MSG_PARTYLISTEND);
}
#define SCREEN_WIDTH 80
#define MAX_VERB_LEN 8
#define VERB_NO 10
static void
view_action_verb(cu, cmd) /* Thor.0726: 新加動詞分類顯示 */
ChatUser *cu;
int cmd;
{
int i;
char *p, *q, *data, *expn, buf[256];
ChatAction *cap;
send_to_user(cu, "/c", 0, MSG_CLRSCR);
data = buf;
if (cmd < '1' || cmd > '3')
{ /* Thor.0726: 寫得不好, 想辦法改進... */
for (i = 0; p = dscrb[i]; i++)
{
sprintf(data, " [//]help %d - MUD-like 社交動詞 第 %d 類", i
+ 1, i + 1);
send_to_user(cu, data, 0, MSG_MESSAGE);
send_to_user(cu, p, 0, MSG_MESSAGE);
send_to_user(cu, " ", 0, MSG_MESSAGE); /* Thor.0726: 換行 */
}
}
else
{
i = cmd - '1';
send_to_user(cu, dscrb[i], 0, MSG_MESSAGE);
expn = buf + 100; /* Thor.0726: 應該不會overlap吧? */
*data = '\0';
*expn = '\0';
cap = catbl[i];
for (i = 0; p = cap[i].verb; i++)
{
q = cap[i].chinese;
strcat(data, p);
strcat(expn, q);
if (((i + 1) % VERB_NO) == 0)
{
send_to_user(cu, data, 0, MSG_MESSAGE);
send_to_user(cu, expn, 0, MSG_MESSAGE); /* Thor.0726: 顯示中文注解 */
*data = '\0';
*expn = '\0';
}
else
{
strncat(data, " ", MAX_VERB_LEN - strlen(p));
strncat(expn, " ", MAX_VERB_LEN - strlen(q));
}
}
if (i % VERB_NO)
{
send_to_user(cu, data, 0, MSG_MESSAGE);
send_to_user(cu, expn, 0, MSG_MESSAGE); /* Thor.0726: 顯示中文注解 */
}
}
/* send_to_user(cu, " ",0); *//* Thor.0726: 換行, 需要 " " 嗎? */
}
/* ----------------------------------------------------- */
/* chat user service routines */
/* ----------------------------------------------------- */
static ChatCmd chatcmdlist[] =
{
"act", chat_act, 0,
"bye", chat_bye, 0,
"chatroom", chat_chatroom, 1, /* Xshadow: for common client */
"clear", chat_clear, 0,
"cloak", chat_cloak, 2,
"date", chat_date, 0,
"flags", chat_setroom, 0,
"help", chat_help, 0,
"ignore", chat_ignore, 1,
"invite", chat_invite, 0,
"join", chat_join, 0,
#ifdef HAVE_KILL_GAME // esp: must follow the 'join' or this will be matched to
'/j'
"jkill",kill_join, 0,
"kstart",kill_start,0,
"kend",kill_end,0,
"kill",kill_kill,1,
"kover",kill_over,0,
"kquery",kill_police_query,0,
"kkk",kill_kkk,1,
"kstate",kill_show_state,1,
// "kvote",kill_vote,1,
// "kkile",kill_user_vote,0,
// "kclearvote",kill_clear_vote,0,
// "kday",kill_sunrise,1,
// "knight",kill_sunset,1,
#endif
"kick", chat_kick, 1,
"msg", chat_private, 0,
"nick", chat_nick, 0,
"operator", chat_makeop, 0,
"party", chat_party, 1, /* Xshadow: party data for common client */
"partyinfo", chat_partyinfo, 1, /* Xshadow: party info for common
* client */
#ifndef STAND_ALONE
"query", chat_query, 0,
#endif
"room", chat_list_rooms, 0,
"unignore", chat_unignore, 1,
"whoin", chat_list_by_room, 1,
"wall", chat_broadcast, 2,
/* fuse.991211 */
"interview", chat_interview, 2,
"who", chat_map_chatids_thisroom, 0,
"list", chat_list_users, 0,
"topic", chat_topic, 1,
"to", chat_towards, 1,
"version", chat_version, 1,
NULL, NULL, 0
};
/* Thor: 0 不用 exact, 1 要 exactly equal, 2 秘密指令 */
static int
command_execute(cu)
ChatUser *cu;
{
char *cmd, *msg, buf[128];
/* Thor.981108: lkchu patch: chatid + msg 只用 80 bytes 不夠, 改為 128 */
ChatCmd *cmdrec;
int match, ch;
msg = cu->ibuf;
match = *msg;
/* Validation routine */
if (cu->room == NULL)
{
/* MUST give special /! or /-! command if not in the room yet */
if (match == '/' && ((ch = msg[1]) == '!' || (ch == '-' && msg[2] == '!')))
{
if (ch == '-')
fprintf(flog, "cli\t[%d] S%d\n", cu->sno, cu->sock);
cu->clitype = (ch == '-') ? 1 : 0;
return (login_user(cu, msg + 2 + cu->clitype));
}
else
{
return -1;
}
}
/* If not a /-command, it goes to the room. */
if (match != '/')
{
if (match)
{
/* fuse.991210: INTERVIEW模式只有op可以說話 */
if (INTERVIEW(cu->room) && (!(ROOMOP(cu))))
return 0;
if (cu->room && !CLOAK(cu)) /* 隱身的人也不能說話哦 */
{
char chatid[16];
sprintf(chatid, "%s:", cu->chatid);
#ifdef HAVE_KILL_GAME
if (cu->room->rflag & ROOM_KILL_STARTED &&
cu->room->currenttalker == cu)
sprintf(buf, "%-10s\033[1;32m%s\033[0m", chatid, msg);
else
sprintf(buf, "%-10s%s", chatid, msg);
#else
sprintf(buf, "%-10s%s", chatid, msg);
#endif
send_to_room(cu->room, buf, cu->userno, MSG_MESSAGE,cu);
}
}
return 0;
}
msg++;
cmd = nextword(&msg);
match = 0;
if (*cmd == '/')
{
cmd++;
if (!*cmd || str_equal("help", cmd))
{
cmd = nextword(&msg); /* Thor.0726: 動詞分類 */
view_action_verb(cu, *cmd);
match = 1;
}
else
{
/* fuse.991210: QUIET模式下不作動作了 */
if (!QUIET(cu->room)) {
if (party_action(cu, cmd, msg) == 0)
match = 1;
else if (speak_action(cu, cmd, msg) == 0)
match = 1;
else
match = condition_action(cu, cmd);
}
}
}
else
{
char *str;
common_client_command = 0;
if (*cmd == '-')
{
if (cu->clitype)
{
cmd++; /* Xshadow: 指令從下一個字元才開始 */
common_client_command = 1;
}
else
{
/* 不是 common client 但送出 common client 指令 -> 假裝沒看到 */
}
}
str_lower(buf, cmd);
for (cmdrec = chatcmdlist; str = cmdrec->cmdstr; cmdrec++)
{
switch (cmdrec->exact)
{
case 1: /* exactly equal */
match = str_equal(str, buf);
break;
case 2: /* Thor: secret command */
if (CHATSYSOP(cu))
match = str_equal(str, buf);
break;
default: /* not necessary equal */
match = str_match(buf, str) >= 0;
break;
}
if (match)
{
cmdrec->cmdfunc(cu, msg);
break;
}
}
}
if (!match)
{
sprintf(buf, "◆ 指令錯誤:/%s", cmd);
send_to_user(cu, buf, 0, MSG_MESSAGE);
}
return 0;
}
/* ----------------------------------------------------- */
/* serve chat_user's connection */
/* ----------------------------------------------------- */
static int
cuser_serve(cu)
ChatUser *cu;
{
int ch, len, isize;
char *str, *cmd, buf[256];
str = buf;
len = recv(cu->sock, str, sizeof(buf) - 1, 0);
if (len < 0)
{
#ifdef HAVE_KILL_GAME
if(0 /* cu->room->rflag & ROOM_KILL_STARTED */)
{
if(cu->killflag & KILL_DROPED)
{
if(time(0) - cu->uptime > 5 * 60) // esp: 5 minutes
{
ch = errno;
exit_room(cu, EXIT_KICK, NULL);
logit("recv", sys_errlist[ch]);
return -1;
}
else
return 1;
}
else
{
// esp: hold this user
exit_room(cu,EXIT_LOSTCONN,NULL);
return 1;
}
}
else
{
ch = errno;
exit_room(cu, EXIT_LOSTCONN, NULL);
logit("recv", sys_errlist[ch]);
return -1;
}
#else
ch = errno;
exit_room(cu, EXIT_LOSTCONN, NULL);
logit("recv", sys_errlist[ch]);
return -1;
#endif
#if 0
if (ch != EWOULDBLOCK)
{
exit_room(cu, EXIT_LOSTCONN, NULL);
logit("recv", sys_errlist[ch]);
return -1;
}
return 0; /* would block, so leave it to do later */
#endif
}
if (len == 0)
{
if (++cu->retry > 100)
return -1;
return 0;
}
#if 0
/* Xshadow: 將送達的資料忠實紀錄下來 */
memcpy(logbuf, buf, sizeof(buf));
for (ch = 0; ch < sizeof(buf); ch++)
if (!logbuf[ch])
logbuf[ch] = '$';
logbuf[len + 1] = '\0';
logit("recv: ", logbuf);
#endif
#if 0
logit(cu->userid, str);
#endif
cu->xdata += len;
isize = cu->isize;
cmd = cu->ibuf + isize;
while (len--)
{
ch = *str++;
if (ch == '\r' || !ch)
continue;
if (ch == '\n')
{
*cmd = '\0';
if (command_execute(cu) < 0)
return -1;
isize = 0;
cmd = cu->ibuf;
continue;
}
if (isize < 79)
{
*cmd++ = ch;
isize++;
}
}
cu->isize = isize;
return 1;
}
/* ----------------------------------------------------- */
/* chatroom server core routines */
/* ----------------------------------------------------- */
static int
/* start_daemon(mode)
int mode; */
servo_daemon(inetd)
int inetd;
{
int fd, value;
char buf[80];
struct sockaddr_in sin;
struct linger ld;
struct rlimit limit;
/*
* More idiot speed-hacking --- the first time conversion makes the C
* library open the files containing the locale definition and time zone.
* If this hasn't happened in the parent process, it happens in the
* children, once per connection --- and it does add up.
*/
time((time_t *) &value);
gmtime((time_t *) &value);
strftime(buf, 80, "%d/%b/%Y:%H:%M:%S", localtime((time_t *) &value));
/* --------------------------------------------------- */
/* speed-hacking DNS resolve */
/* --------------------------------------------------- */
dns_init();
#if 0
gethostname(buf, sizeof(buf));
gethostbyname(buf);
#endif
/* --------------------------------------------------- */
/* adjust the resource limit */
/* --------------------------------------------------- */
getrlimit(RLIMIT_NOFILE, &limit);
limit.rlim_cur = limit.rlim_max;
setrlimit(RLIMIT_NOFILE, &limit);
limit.rlim_cur = limit.rlim_max = 4 * 1024 * 1024;
setrlimit(RLIMIT_DATA, &limit);
#ifdef SOLARIS
#define RLIMIT_RSS RLIMIT_AS
/* Thor.981206: port for solaris 2.6 */
#endif
setrlimit(RLIMIT_RSS, &limit);
limit.rlim_cur = limit.rlim_max = 0;
setrlimit(RLIMIT_CORE, &limit);
#if 0
limit.rlim_cur = limit.rlim_max = 60 * 20;
setrlimit(RLIMIT_CPU, &limit);
#endif
/* --------------------------------------------------- */
/* detach daemon process */
/* --------------------------------------------------- */
close(2);
close(1);
/* if (mode > 1) */
if(inetd)
return 0;
close(0);
if (fork())
exit(0);
setsid();
if (fork())
exit(0);
/* --------------------------------------------------- */
/* bind the service port */
/* --------------------------------------------------- */
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
/*
* timeout 方面, 將 socket 改成 O_NDELAY (no delay, non-blocking),
* 如果能順利送出資料就送出, 不能送出就算了, 不再等待 TCP_TIMEOUT 時間。
* (default 是 120 秒, 并且有 3-way handshaking 機制, 有可能一等再等)。
*/
#if 1
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NDELAY);
#endif
value = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &value, sizeof(value));
value = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &value, sizeof(value));
ld.l_onoff = ld.l_linger = 0;
setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &ld, sizeof(ld));
sin.sin_family = AF_INET;
sin.sin_port = htons(CHAT_PORT);
sin.sin_addr.s_addr = htonl(INADDR_ANY);
memset(sin.sin_zero, 0, sizeof(sin.sin_zero));
if ((bind(fd, (struct sockaddr *) & sin, sizeof(sin)) < 0) ||
(listen(fd, SOCK_QLEN) < 0))
exit(1);
return fd;
}
#ifdef SERVER_USAGE
static void
server_usage()
{
struct rusage ru;
if (getrusage(RUSAGE_SELF, &ru))
return;
fprintf(flog, "\n[Server Usage]\n\n"
"user time: %.6f\n"
"system time: %.6f\n"
"maximum resident set size: %lu P\n"
"integral resident set size: %lu\n"
"page faults not requiring physical I/O: %d\n"
"page faults requiring physical I/O: %d\n"
"swaps: %d\n"
"block input operations: %d\n"
"block output operations: %d\n"
"messages sent: %d\n"
"messages received: %d\n"
"signals received: %d\n"
"voluntary context switches: %d\n"
"involuntary context switches: %d\n"
"gline: %d\n\n",
(double) ru.ru_utime.tv_sec + (double) ru.ru_utime.tv_usec / 1000000.0,
(double) ru.ru_stime.tv_sec + (double) ru.ru_stime.tv_usec / 1000000.0,
ru.ru_maxrss,
ru.ru_idrss,
ru.ru_minflt,
ru.ru_majflt,
ru.ru_nswap,
ru.ru_inblock,
ru.ru_oublock,
ru.ru_msgsnd,
ru.ru_msgrcv,
ru.ru_nsignals,
ru.ru_nvcsw,
ru.ru_nivcsw,
gline);
fflush(flog);
}
#endif
static void
reaper()
{
while (waitpid(-1, NULL, WNOHANG | WUNTRACED) > 0)
;
}
static void
sig_trap(sig)
int sig;
{
char buf[80];
sprintf(buf, "signal [%d] at line %d (errno: %d)", sig, gline, errno);
logit("EXIT", buf);
fclose(flog);
exit(1);
}
static void
sig_over()
{
int fd;
server_usage();
logit("OVER", "");
fclose(flog);
for (fd = 0; fd < 64; fd++)
close(fd);
execl("bin/xchatd", NULL);
}
static void
main_signals()
{
struct sigaction act;
/* sigblock(sigmask(SIGPIPE)); */
/* Thor.981206: 統一 POSIX 標准用法 */
/* act.sa_mask = 0; */ /* Thor.981105: 標准用法 */
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = sig_trap;
sigaction(SIGBUS, &act, NULL);
sigaction(SIGSEGV, &act, NULL);
sigaction(SIGTERM, &act, NULL);
act.sa_handler = sig_over;
sigaction(SIGXCPU, &act, NULL);
act.sa_handler = reaper;
sigaction(SIGCHLD, &act, NULL);
#ifdef SERVER_USAGE
act.sa_handler = server_usage;
sigaction(SIGPROF, &act, NULL);
#endif
/* Thor.981206: lkchu patch: 統一 POSIX 標准用法 */
/* 在此借用 sigset_t act.sa_mask */
sigaddset(&act.sa_mask, SIGPIPE);
sigprocmask(SIG_BLOCK, &act.sa_mask, NULL);
}
int
main(argc, argv)
int argc;
char *argv[];
{
int sock, nfds, maxfds, servo_sno;
ChatUser *cu,/* *userpool,*/ **FBI;
time_t uptime, tcheck;
fd_set rset, xset;
static struct timeval tv = {CHAT_INTERVAL, 0};
struct timeval tv_tmp; /* Thor.981206: for future reservation bug */
sock = 0;
while ((nfds = getopt(argc, argv, "hid")) != -1)
{
switch (nfds)
{
case 'i':
sock = 1;
break;
case 'd':
break;
case 'h':
default:
fprintf(stderr, "Usage: %s [options]\n"
"\t-i start from inetd with wait option\n"
"\t-d debug mode\n"
"\t-h help\n",
argv[0]);
exit(0);
}
}
servo_daemon(sock);
/* start_daemon(argc); */
setgid(BBSGID);
setuid(BBSUID);
chdir(BBSHOME);
umask(077);
log_init();
main_signals();
/* --------------------------------------------------- */
/* init variable : rooms & users */
/* --------------------------------------------------- */
userpool = NULL;
strcpy(mainroom.name, MAIN_NAME);
strcpy(mainroom.topic, MAIN_TOPIC);
/* --------------------------------------------------- */
/* main loop */
/* --------------------------------------------------- */
tcheck = 0;
servo_sno = 0;
for (;;)
{
uptime = time(0);
if (tcheck < uptime)
{
nfds = maxfds = 0;
FD_ZERO(&mainfset);
FD_SET(0, &mainfset);
tcheck = uptime - CHAT_INTERVAL;
for (FBI = &mainuser; cu = *FBI;)
{
if (cu->uptime < tcheck)
{
cuser_free(cu);
*FBI = cu->unext;
cu->unext = userpool;
userpool = cu;
}
else
{
nfds++;
sock = cu->sock;
FD_SET(sock, &mainfset);
if (maxfds < sock)
maxfds = sock;
FBI = &(cu->unext);
}
}
totaluser = nfds;
fprintf(flog, "MAINTAIN %d user (%d)\n", nfds, maxfds++);
fflush(flog);
tcheck = uptime + CHAT_INTERVAL;
}
/* ------------------------------------------------- */
/* Set up the fdsets */
/* ------------------------------------------------- */
rset = mainfset;
xset = mainfset;
/* Thor.981206: for future reservation bug */
tv_tmp = tv;
nfds = select(maxfds, &rset, NULL, &xset, &tv_tmp);
#if 0
{
char buf[32];
static int xxx;
if ((++xxx & 8191) == 0)
{
sprintf(buf, "%d/%d", nfds, maxfds);
logit("MAIN", buf);
}
}
#endif
if (nfds == 0)
{
continue;
}
if (nfds < 0)
{
sock = errno;
if (sock != EINTR)
{
logit("select", sys_errlist[sock]);
}
continue;
}
/* ------------------------------------------------- */
/* serve active agents */
/* ------------------------------------------------- */
uptime = time(0);
for (FBI = &mainuser; cu = *FBI;)
{
sock = cu->sock;
if (FD_ISSET(sock, &rset))
{
static int xxx, xno;
nfds = cuser_serve(cu);
if ((++xxx & 511) == 0)
{
int sno;
sno = cu->sno;
fprintf(flog, "rset\t[%d] S%d R%d %d\n", sno, sock, nfds, xxx);
if (sno == xno)
nfds = -1;
else
xno = sno;
}
}
else if (FD_ISSET(sock, &xset))
{
nfds = -1;
}
else
{
nfds = 0;
}
if (nfds < 0 || cu->uptime <= 0) /* free this client */
{
cuser_free(cu);
*FBI = cu->unext;
cu->unext = userpool;
userpool = cu;
continue;
}
if (nfds > 0)
{
cu->uptime = uptime;
}
FBI = &(cu->unext);
}
/* ------------------------------------------------- */
/* accept new connection */
/* ------------------------------------------------- */
if (FD_ISSET(0, &rset))
{
{
static int yyy;
if ((++yyy & 2047) == 0)
fprintf(flog, "conn\t%d\n", yyy);
}
for (;;)
{
int value;
struct sockaddr_in sin;
value = sizeof(sin);
sock = accept(0, (struct sockaddr *) &sin, &value);
if (sock > 0)
{
if (cu = userpool)
{
userpool = cu->unext;
}
else
{
cu = (ChatUser *) malloc(sizeof(ChatUser));
}
*FBI = cu;
/* variable initialization */
memset(cu, 0, sizeof(ChatUser));
cu->sock = sock;
cu->tbegin = uptime;
cu->uptime = uptime;
cu->sno = ++servo_sno;
cu->xdata = 0;
cu->retry = 0;
memcpy(cu->rhost, &sin.sin_addr, sizeof(struct in_addr));
totaluser++;
FD_SET(sock, &mainfset);
if (sock >= maxfds)
maxfds = sock + 1;
{
int value;
value = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
(char *) &value, sizeof(value));
}
#if 1
fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NDELAY);
#endif
fprintf(flog, "CONN\t[%d] %d %s\n",
servo_sno, sock, str_time(&cu->tbegin));
break;
}
nfds = errno;
if (nfds != EINTR)
{
logit("accept", sys_errlist[nfds]);
break;
}
#if 0
while (waitpid(-1, NULL, WNOHANG | WUNTRACED) > 0);
#endif
}
}
/* ------------------------------------------------- */
/* tail of main loop */
/* ------------------------------------------------- */
}
}
#ifdef HAVE_KILL_GAME
static void kill_clear_user_vote(room)
ChatRoom *room;
{
ChatUser *user;
if(!room)
return ;
for(user = mainuser;user;user = user->unext)
{
if(!user->userno)
continue;
if(user->room != room)
continue;
user->votenum = 0;
}
}
static void kill_enable_police_query(room)
ChatRoom *room;
{
ChatUser *user;
if(!room)
return ;
for(user = mainuser;user;user = user->unext)
{
if(!user->userno)
continue;
if(user->room != room)
continue;
if(KILL_ROLE(user) == KILL_POLICE)
user->killflag &= ~KILL_QUERYED;
}
}
static void kill_enable_user_talk(room)
ChatRoom *room;
{
ChatUser *user;
if(!room)
return ;
for(user = mainuser;user;user = user->unext)
{
if(!user->userno)
continue;
if(user->room != room)
continue;
user->killflag &= ~KILL_TALKED;
}
}
static void kill_enable_user_vote(room)
ChatRoom *room;
{
ChatUser *user;
if(!room)
return ;
for(user = mainuser;user;user = user->unext)
{
if(!user->userno)
continue;
if(user->room != room)
continue;
user->killflag &= ~KILL_VOTED;
}
}
#if 0
static void kill_clear_vote(cu,msg)
ChatUser* cu;
char* msg;
{
ChatRoom *room;
room = cu->room;
if(room == ROOM_ALL || !(room->rflag & ROOM_KILLGAME))
{
send_to_user(cu,"$$ 這個房間不是遊戲房間",0,MSG_MESSAGE);
return;
}
if(!(room->rflag & ROOM_KILL_STARTED))
{
send_to_user(cu,"$$ 這個房間的遊戲還沒有開始",0,MSG_MESSAGE);
return;
}
if(KILL_ROLE(cu) != KILL_JUDGE)
{
send_to_user(cu,"$$ 你不是法官,不能清除投票記錄",0,MSG_MESSAGE);
return;
}
if(room->killstatus != KILL_AFTERDAY)
{
send_to_user(cu,"$$ 現在沒有進行投票",0,MSG_MESSAGE);
return;
}
kill_clear_user_vote(room);
kill_enable_user_vote(room);
kill_refresh_table(room);
send_to_room(room,"$$ 現在大家重新投票吧",0,MSG_MESSAGE,cu);
}
#endif
static void kill_clear_user_state(room)
ChatRoom *room;
{
ChatUser *user;
if(!room)
return ;
room->currenttalker = NULL;
for(user = mainuser;user;user = user->unext)
{
if(!user->userno)
continue;
if(user->room != room)
continue;
user->killflag = 0;
user->killstate = 0;
user->votenum = 0;
}
return ;
}
static ChatUser* kill_find_just_killed(room)
ChatRoom *room;
{
ChatUser *user;
if(!room)
return NULL;
for(user = mainuser;user;user = user->unext)
{
if(user->room != room)
continue;
if(user->killflag & KILL_KILLED && !(user->killflag & KILL_KNOCKOUT))
return user;
}
return NULL;
}
static int chat_get_user_number(room)
ChatRoom *room;
{
ChatUser *user;
int count = 0;
if(!room)
return 0;
/* esp: no cloak , to prevent cheating */
for(user = mainuser;user;user = user->unext)
{
if(!user->userno)
continue;
if(user->room != room)
continue;
count ++;
}
return count;
}
static ChatUser *chat_get_nth_user(room, nth)
ChatRoom *room;
int nth;
{
ChatUser *user;
int count = 0;
if(!room)
return NULL;
for(user = mainuser;user;user = user->unext)
{
if(!user->userno)
continue;
if(user->room != room)
continue;
count ++;
if(count == nth)
break;
}
return user;
}
static int kill_get_user_state(whichroom, cu, user)
ChatRoom *whichroom;
ChatUser *cu;
ChatUser *user;
{
ChatRoom *room;
room = cu->room;
if(room != whichroom)
return KILL_USER_UNKNOWN;
if(!(room->rflag & ROOM_KILL_STARTED))
return KILL_USER_UNKNOWN;
if(cu == user)
return user->killstate;
if(KILL_ROLE(cu) == KILL_KILLER)
{
if(KILL_ROLE(user) == KILL_KILLER)
return user->killstate;
}
/* esp: 大家覺得警察太強大了 */
else if(KILL_ROLE(cu) == KILL_POLICE
&& room->rflag & ROOM_KILL_STRPOLICE
&& user->killflag & KILL_QUERYED
&& !(cu->killflag & KILL_KILLED))
{
return user->killstate;
}
/* esp: zk 又說了,殺手隱藏得很深…… */
/*
else if(KILL_ROLE(cu) == KILL_NORMAL)
{
if(user->killstate == KILL_USER_KILLED_KILLER
&& user->killflag & KILL_KNOCKOUT)
return user->killstate;
}
*/
if(room->killstatus == KILL_DAY_MURDERED || room->killstatus == KILL_DAY_TALK
|| room->killstatus == KILL_DAY_VOTE || room->killstatus == KILL_AFTERDAY)
if(user->killflag & KILL_KILLED && !(user->killflag & KILL_KNOCKOUT))
return KILL_USER_JUSTKILLED;
if(user->killflag & KILL_KNOCKOUT)
return KILL_USER_JUSTKILLED;
return KILL_USER_UNKNOWN;
}
static int kill_can_talk(room,user)
ChatRoom *room;
ChatUser *user;
{
/* esp: return 1 means ok, 0 means can't */
if(!(room->rflag & ROOM_KILLGAME))
return 1;
if(!(room->rflag & ROOM_KILL_STARTED))
return 1;
if(room->rflag & ROOM_KILL_WAITDROP)
return 1;
if(user->killflag & KILL_KNOCKOUT
&& !(room->rflag & ROOM_KILL_NOGHOST))
return 1;
if(room->killstatus == KILL_DAY_TALK
&& room->rflag & ROOM_KILL_DISCUSS)
return 1; // esp : for argue..;)
if(room->currenttalker == NULL)
return 1;
if(room->killstatus == KILL_DAY_TALK
|| room->killstatus == KILL_BEFORENIGHT)
{
if(room->currenttalker == user)
return 1;
else
return 0;
}
return 1;
}
static int kill_can_talk_between(room, user1, user2)
ChatRoom *room;
ChatUser *user1;
ChatUser *user2;
{
/* esp: return 1 means ok, 0 means can't */
/* What's more. this function only detect if user1 can send
message to user2, doesn't care about user2 to user1 */
int rc = 0;
kill_talk_time_check(room);
kill_vote_time_check(room);
if(!(room->rflag & ROOM_KILLGAME))
return 1;
if(!(room->rflag & ROOM_KILL_STARTED))
return 1;
if(room->rflag & ROOM_KILL_WAITDROP)
return 1;
if(user1->killflag & KILL_KNOCKOUT
&& !(room->rflag & ROOM_KILL_NOGHOST))
return 1;
switch(room->killstatus)
{
case KILL_NIGHT_KILLER:
if((KILL_ROLE(user1) == KILL_KILLER)
&& KILL_ROLE(user2) == KILL_KILLER)
rc = 1;
break;
case KILL_NIGHT_POLICE:
if((KILL_ROLE(user1) == KILL_POLICE)
&& KILL_ROLE(user2) == KILL_POLICE)
rc = 1;
break;
case KILL_DAY_MURDERED:
if(user1->killflag & KILL_KILLED && !(user1->killflag & KILL_KNOCKOUT)
&& room->currenttalker == user1)
rc = 1;
break;
case KILL_DAY_TALK:
if(
(!(user1->killflag & KILL_KILLED) && room->currenttalker == user1)
|| room->rflag & ROOM_KILL_DISCUSS)
rc = 1;
else
rc = 0;
break;
case KILL_DAY_VOTE:
rc = 0;
break;
case KILL_AFTERDAY:
if(room->currenttalker == user1)
rc = 1;
else
rc = 0;
break;
case KILL_BEFORENIGHT:
if(user1->killflag & KILL_KILLED && !(user1->killflag & KILL_KNOCKOUT))
rc = 1;
break;
}
return rc;
}
static void kill_random_role(room)
ChatRoom *room;
{
/* esp: the number of roles should be indicated now,
we random them to guys step by step now.
judge, police, killer, the left are normal guys.
*/
int count,countnow;
int i,r;
ChatUser *user;
char buf[200];
countnow = count = chat_get_user_number(room);
if(count == 0)
return;
srand(time(NULL));
/* policemen */
for(i = 0;i<room->policenum;i++)
{
r = (float) rand() / RAND_MAX * countnow;
do
{
user = chat_get_nth_user(room,r+1);
r = (r + 1) % count;
}while(KILL_ROLE(user) != KILL_NONE);
// esp: don't allow police query at the beginning
user->killflag = KILL_POLICE | KILL_QUERYED;
user->killstate = KILL_USER_POLICE;
sprintf(buf,"\033[1;33m$$ 您的角色是\033[0m %s%s%s ",
userkillstatecolors[user->killstate],userkillstates[user->killstate],
"\033[0m");
send_to_user(user,"\033[1;33m$$\033[0m",0,MSG_MESSAGE,NULL);
send_to_user(user,buf,0,MSG_MESSAGE,NULL);
send_to_user(user,"\033[1;33m$$\033[0m",0,MSG_MESSAGE,NULL);
countnow --;
}
/* killers */
for(i = 0;i<room->killernum;i++)
{
r = (float) rand() / RAND_MAX * countnow;
do
{
user = chat_get_nth_user(room,r+1);
r = (r + 1) % count;
}while(KILL_ROLE(user) != KILL_NONE);
user->killflag = KILL_KILLER;
user->killstate = KILL_USER_KILLER;
sprintf(buf,"\033[1;33m$$ 您的角色是\033[0m %s%s%s ",
userkillstatecolors[user->killstate],userkillstates[user->killstate],
"\033[0m");
send_to_user(user,"\033[1;33m$$\033[0m",0,MSG_MESSAGE,NULL);
send_to_user(user,buf,0,MSG_MESSAGE,NULL);
send_to_user(user,"\033[1;33m$$\033[0m",0,MSG_MESSAGE,NULL);
countnow --;
}
/* normal guys */
for(i = 0;i<countnow;i++)
{
r = i;
do
{
user = chat_get_nth_user(room,r+1);
r = (r + 1) % count;
}while(KILL_ROLE(user) != KILL_NONE);
user->killflag = KILL_NORMAL;
user->killstate = KILL_USER_NORMAL;
sprintf(buf,"\033[1;33m$$ 您的角色是\033[0m %s%s%s ",
userkillstatecolors[user->killstate],userkillstates[user->killstate],
"\033[0m");
send_to_user(user,"\033[1;33m$$\033[0m",0,MSG_MESSAGE,NULL);
send_to_user(user,buf,0,MSG_MESSAGE,NULL);
send_to_user(user,"\033[1;33m$$\033[0m",0,MSG_MESSAGE,NULL);
}
return;
}
/* esp: return 1 means game done, 0 means not done */
static int kill_is_finished(room)
ChatRoom* room;
{
int killernum = 0,policenum = 0,normalnum = 0;
ChatUser *user;
int rc = 0;
if(!room)
return 0;
for(user = mainuser;user;user = user->unext)
{
if(user->room != room)
continue;
if(user->killflag & KILL_KILLED)
{
if(KILL_ROLE(user)==KILL_POLICE)
policenum ++;
else if(KILL_ROLE(user)==KILL_KILLER)
killernum ++;
else if(KILL_ROLE(user)==KILL_NORMAL)
normalnum ++;
}
}
if((room->policenum - policenum) + (room->normalnum - normalnum) <= room->kil
lernum - killernum)
{
send_to_room(room,"\033[1;31m$$ $$ \033[5m殺手們已經占據了多數,殺手們勝利了
。\033[0m \033[1;31m$$ $$\033[0m",0,MSG_MESSAGE,NULL);
rc = 1;
}
else if(killernum == room->killernum)
{
send_to_room(room,"\033[1;32m$$ $$ \033[5m 殺手全部抓獲,警察與平民勝利了。
\033[0m \033[1;32m$$ $$\033[0m",0,MSG_MESSAGE,NULL);
rc = 2;
}
if(rc != 0)
for(user = mainuser;user;user = user->unext)
{
if(user->room != room)
continue;
if(KILL_ROLE(user) == KILL_KILLER)
{
if(rc == 1)
kill_log_state(user,1);
else if(rc == 2)
kill_log_state(user,2);
}
else
{
if(rc == 1)
kill_log_state(user,2);
else if(rc == 2)
kill_log_state(user,1);
}
}
return rc;
}
static void kill_next_status(room, cu)
ChatRoom* room;
ChatUser* cu;
{
ChatUser *user;
char buf[80];
if(kill_is_finished(room))
{
room->killstatus = KILL_NOT_START;
send_to_room(room,"\033[1;33m$$$$$$ 這一輪遊戲結束了 $$$$$$\033[0m",0,MSG_M
ESSAGE,NULL);
kill_refresh_table(room);
room->rflag &= ~ROOM_KILL_STARTED;
kill_clear_user_state(room);
return;
}
kill_clear_user_vote(room);
kill_enable_user_talk(room);
kill_enable_user_vote(room);
room->currenttalker = NULL;
switch(room->killstatus)
{
case KILL_NOT_START:
room->killstatus = KILL_NIGHT_KILLER;
room->tvotebegin = time(0);
send_to_room(room,"\033[1;33m$$ 現在黑夜開始了,殺手請投票殺人吧(/k
ill <user>)\033[0m",0,MSG_MESSAGE,NULL);
break;
case KILL_NIGHT_KILLER:
room->killstatus = KILL_NIGHT_POLICE;
if(room->rflag & ROOM_KILL_STRPOLICE)
kill_show_next_killer(room);
else
kill_enable_police_query(room);
if(room->policenum > 0)
send_to_room(room,"\033[1;33m$$ 現在殺手消失了,警察們出來了,他們
發現了殺手\033[0m",0,MSG_MESSAGE,NULL);
// kill_refresh_table(room);
// break; // esp: 警察需要查詢才知道殺手是誰。
case KILL_NIGHT_POLICE:
room->killstatus = KILL_DAY_MURDERED;
send_to_room(room,"\033[1;33m$$ 天亮了,大家的眼睛都睜開了\033[0m",
0,MSG_MESSAGE,NULL);
user = kill_find_just_killed(room);
if(user)
{
sprintf(buf,"\033[1;33m$$ 很不幸, %s 被暗殺了\033[0m",user->chat
id);
send_to_room(room,buf,0,MSG_MESSAGE,NULL);
room->currenttalker = user;
user->tkillbegin = time(0);
}
send_to_room(room,"\033[1;33m$$ 現在請聽被害人發言,結束發言請用/ko
\033[0m",0,MSG_MESSAGE,NULL);
break;
case KILL_DAY_MURDERED:
user = kill_find_just_killed(room);
if(user)
{
user->killflag |= KILL_KNOCKOUT;
}
room->killstatus = KILL_DAY_TALK;
send_to_room(room,"\033[1;33m$$ 現在大家輪流發言,發表自己的看法\03
3[0m",0,MSG_MESSAGE,NULL);
user = kill_get_next_user(room,NULL);
if(user)
{
room->currenttalker = user;
user->tkillbegin = time(0);
sprintf(buf,"\033[1;33m$$ 現在由 %s 發言,結束請用/ko\033[0m",use
r->chatid);
send_to_room(room,buf,0,MSG_MESSAGE,NULL);
}
break;
case KILL_DAY_TALK:
room->killstatus = KILL_DAY_VOTE;
room->tvotebegin = time(0);
send_to_room(room,"\033[1;33m$$ 現在開始投票,你的決定將決定一個人的
生死(/kill <user>)\033[0m",0,MSG_MESSAGE,NULL);
break;
case KILL_DAY_VOTE:
case KILL_AFTERDAY:
user = kill_find_just_killed(room);
if(user)
{
#if 0 // esp: zk told me that either killer or other should have the chance to
speak
if(KILL_ROLE(user) == KILL_KILLER)
{
sprintf(buf,"\033[1;33m$$ 殺手 %s 被抓獲了!\033[0m",user->chat
id);
send_to_room(room, buf, 0, MSG_MESSAGE, NULL);
user->killflag |= KILL_KNOCKOUT;
room->killstatus = KILL_NOT_START;
kill_next_status(room,cu);
}
else
#endif
{
sprintf(buf,"\033[1;33m$$ %s 被殺害了!\033[0m",user->chatid);
send_to_room(room, buf, 0, MSG_MESSAGE, NULL);
send_to_room(room, "\033[1;33m$$ 讓我們來聽聽他有什麼話要說\033
[0m", 0, MSG_MESSAGE, NULL);
room->killstatus = KILL_BEFORENIGHT;
room->currenttalker = user;
user->tkillbegin = time(0);
kill_refresh_table(room);
}
}
break;
case KILL_BEFORENIGHT:
user = kill_find_just_killed(room);
if(user)
{
user->killflag |= KILL_KNOCKOUT;
}
room->killstatus = KILL_NIGHT_KILLER;
send_to_room(room,"\033[1;33m$$ 現在黑夜開始了,殺手請投票殺人吧(/k
ill <user>)\033[0m",0,MSG_MESSAGE,NULL);
break;
}
kill_refresh_table(room);
return;
}
static void kill_start(cu, msg)
ChatUser* cu;
char* msg;
{
int count;
char buf[128];
ChatRoom *room = cu->room;
if(room == ROOM_ALL || !(room->rflag & ROOM_KILLGAME))
{
send_to_user(cu,"※ 對不起,這個房間不是遊戲房間",0,MSG_MESSAGE);
return ;
}
if(!ROOMOP(cu))
{
send_to_user(cu, msg_not_op, 0, MSG_MESSAGE);
return ;
}
if(room->rflag & ROOM_KILL_STARTED)
{
send_to_user(cu, "※ 遊戲已經開始了",0,MSG_MESSAGE);
return ;
}
count = chat_get_user_number(room);
if(count < 7)
{
send_to_user(cu,"※ 對不起,這個房間裡的人太少了,至少要7個人",0,MSG_MESSAG
E);
return ;
}
if(count > 15)
{
send_to_user(cu,"※ 對不起,這個房間裡的人太多了,最多要15個人",0,MSG_MESSA
GE);
return ;
}
/* clear the top table */
sprintf(buf,"/u2%80s"," ");
send_to_room(room, buf, 0, MSG_MESSAGE,NULL);
sprintf(buf,"/u3%80s"," ");
send_to_room(room, buf, 0, MSG_MESSAGE,NULL);
sprintf(buf,"/u4%80s"," ");
send_to_room(room, buf, 0, MSG_MESSAGE,NULL);
room->rflag &= 0x2F;
kill_clear_user_state(room);
kill_parse_start_options(room,msg);
if(count >= 7 && count < 10)
{
room->policenum = 0;
if(room->rflag & ROOM_KILL_POLICE)
room->policenum = 1;
if(room->rflag & ROOM_KILL_NOPOLICE)
room->policenum = 0;
room->killernum = 2;
room->normalnum = count - room->policenum - room->killernum ;
}
if(count >= 10 && count <= 15)
{
room->policenum = 1;
if(room->rflag & ROOM_KILL_POLICE)
room->policenum = 1;
if(room->rflag & ROOM_KILL_NOPOLICE)
room->policenum = 0;
room->killernum = 3;
room->normalnum = count - room->policenum - room->killernum ;
}
else if(count >= 15 && count <= 20 )
{
room->policenum = 2;
if(room->rflag & ROOM_KILL_POLICE)
room->policenum = 1;
if(room->rflag & ROOM_KILL_NOPOLICE)
room->policenum = 0;
room->killernum = 4;
room->normalnum = count - room->policenum - room->killernum ;
}
/*
else if(count >= 15)
{
room->policenum = 4;
room->killernum = 4;
room->normalnum = count - room->policenum - room->killernum ;
}
*/
send_to_room(room,"/c",0,MSG_MESSAGE,NULL);
send_to_room(room,"\033[1;33m$$ 新一輪殺手遊戲開始了!\033[0m",0,MSG_
MESSAGE,NULL);
if(room->rflag & ROOM_KILL_DISCUSS)
send_to_room(room,"\033[1;33m$$ 可以進行討論\033[0m",0,MSG_MESSAGE,
NULL);
else
send_to_room(room,"\033[1;33m$$ 不可以進行討論\033[0m",0,MSG_MESSAG
E,NULL);
if(room->rflag & ROOM_KILL_NOGHOST)
send_to_room(room,"\033[1;33m$$ 死人不可以說話\033[0m",0,MSG_MESSAG
E,NULL);
else
send_to_room(room,"\033[1;33m$$ 死人可以說話\033[0m",0,MSG_MESSAGE,
NULL);
if(room->policenum > 0)
{
if(room->rflag & ROOM_KILL_STRPOLICE)
send_to_room(room,"\033[1;33m$$ 警察每天開始發現一個殺手\033[0m",
0,MSG_MESSAGE,NULL);
else
send_to_room(room,"\033[1;33m$$ 警察每天可以查詢一次\033[0m",0,MS
G_MESSAGE,NULL);
sprintf(buf,"\033[1;33m$$ 共有 %d 名警察、%d 名殺手和 %d 名平民\033
[0m",room->policenum,room->killernum,room->normalnum);
}
else
sprintf(buf,"\033[1;33m$$ 共有 %d 名殺手和 %d 名平民\033[0m",room->
killernum,room->normalnum);
send_to_room(room,buf,0,MSG_MESSAGE,NULL);
kill_random_role(room);
if(count % 2 == 0) // esp: 偶數夜間開始
{
send_to_room(room,"\033[1;33m$$ 因為玩家數為偶數,所以從晚上開始、\
033[0m",0,MSG_MESSAGE,NULL);
room->killstatus = KILL_NOT_START;
}
else // 奇數白天發言開始
{
send_to_room(room,"\033[1;33m$$ 因為玩家數為奇數,所以從白天開始、\
033[0m",0,MSG_MESSAGE,NULL);
room->killstatus = KILL_DAY_MURDERED;
}
room->rflag |= ROOM_KILL_STARTED;
kill_next_status(room,cu);
}
static void kill_end(cu, msg)
ChatUser* cu;
char* msg;
{
ChatRoom *room = cu->room;
if(room == ROOM_ALL || !(room->rflag & ROOM_KILLGAME))
{
send_to_user(cu,"※ 對不起,這個房間不是遊戲房間",0,MSG_MESSAGE);
return ;
}
if(cu != NULL && !ROOMOP(cu))
{
send_to_user(cu, msg_not_op, 0, MSG_MESSAGE);
return ;
}
if(!(room->rflag & ROOM_KILL_STARTED))
{
send_to_user(cu, "※ 遊戲還沒開始呢",0,MSG_MESSAGE);
return ;
}
send_to_room(room,"\033[1;33m$$ 這一輪的遊戲被提前結束了\033[0m",0,MS
G_MESSAGE,NULL);
room->rflag &= ~ROOM_KILL_STARTED;
room->killstatus = KILL_NOT_START;
kill_refresh_table(room);
kill_clear_user_state(room);
}
#if 0
static void kill_sunset(cu,msg)
ChatUser* cu;
char* msg;
{
ChatRoom *room;
room = cu->room;
if(room == ROOM_ALL || !(room->rflag & ROOM_KILLGAME))
{
send_to_user(cu,"$$ 這個房間不是遊戲房間",0,MSG_MESSAGE);
return;
}
if(!(room->rflag & ROOM_KILL_STARTED))
{
send_to_user(cu,"$$ 這個房間的遊戲還沒有開始",0,MSG_MESSAGE);
return;
}
if(KILL_ROLE(cu) != KILL_JUDGE)
{
send_to_user(cu,"$$ 你不是法官,不能使天黑下去",0,MSG_MESSAGE);
return;
}
if(room->killstatus != KILL_BEFORENIGHT)
{
send_to_user(cu,"$$ 現在還沒到天黑的時候呢",0,MSG_MESSAGE);
return;
}
kill_next_status(room,cu);
cu->killstate = KILL_JUDGE_FRESH;
}
static void kill_sunrise(cu,msg)
ChatUser* cu;
char* msg;
{
ChatRoom *room;
room = cu->room;
if(room == ROOM_ALL || !(room->rflag & ROOM_KILLGAME))
{
send_to_user(cu,"$$ 這個房間不是遊戲房間",0,MSG_MESSAGE);
return;
}
if(!(room->rflag & ROOM_KILL_STARTED))
{
send_to_user(cu,"$$ 這個房間的遊戲還沒有開始",0,MSG_MESSAGE);
return;
}
if(KILL_ROLE(cu) != KILL_JUDGE)
{
send_to_user(cu,"$$ 你不是法官,不能使天亮起來",0,MSG_MESSAGE);
return;
}
if(room->killstatus != KILL_NIGHT_POLICE)
{
send_to_user(cu,"$$ 現在還不是后半夜呢",0,MSG_MESSAGE);
return;
}
kill_next_status(room,cu);
cu->killstate = KILL_JUDGE_FRESH;
}
static void kill_vote(cu,msg)
ChatUser* cu;
char* msg;
{
ChatRoom *room;
room = cu->room;
if(room == ROOM_ALL || !(room->rflag & ROOM_KILLGAME))
{
send_to_user(cu,"\033[1;35m$$ 這個房間不是遊戲房間\033[0m",0,MSG_MESSAGE);
return;
}
if(!(room->rflag & ROOM_KILL_STARTED))
{
send_to_user(cu,"$$ 這個房間的遊戲還沒有開始",0,MSG_MESSAGE);
return;
}
if(KILL_ROLE(cu) != KILL_JUDGE)
{
send_to_user(cu,"$$ 你不是法官,不能執行投票",0,MSG_MESSAGE);
return;
}
if(room->killstatus != KILL_DAY)
{
send_to_user(cu,"$$ 現在還不能投票",0,MSG_MESSAGE);
return;
}
kill_next_status(room,cu);
cu->killstate = KILL_JUDGE_FRESH;
}
#endif
static void kill_kill(cu,msg)
ChatUser* cu;
char* msg;
{
ChatRoom *room;
char *twit,buf[80];
ChatUser *xuser;
room = cu->room;
if(room == ROOM_ALL || !(room->rflag & ROOM_KILLGAME))
{
send_to_user(cu,"\033[1;35m$$ 這個房間不是遊戲房間\033[0m",0,MSG_MESSAGE);
return;
}
if(!(room->rflag & ROOM_KILL_STARTED))
{
send_to_user(cu,"\033[1;35m$$ 這個房間的遊戲還沒有開始\033[0m",0,MSG_MESSAG
E);
return;
}
if(room->rflag & ROOM_KILL_WAITDROP)
{
send_to_user(cu,"\033[1;35m$$ 還是先等等斷線的同志吧。\033[0m",0,MSG_MESSAG
E);
return;
}
if(cu->killflag & KILL_KILLED)
{
send_to_user(cu,"\033[1;35m$$ 死人就不能再殺別人了:(\033[0m",0,MSG_MESSAGE)
;
return;
}
if(room->killstatus != KILL_NIGHT_KILLER && room->killstatus != KILL_DAY_VOT
E)
{
send_to_user(cu,"\033[1;35m$$ 現在還不能殺人\033[0m",0,MSG_MESSAGE);
return;
}
twit = nextword(&msg);
xuser = cuser_by_chatid(twit);
if(xuser == NULL)
{
xuser = cuser_by_userid(twit);
}
if(xuser == NULL || xuser->room != room)
{
sprintf(buf, msg_no_such_id, twit);
send_to_user(cu, buf, 0, MSG_MESSAGE);
return;
}
if(room->killstatus == KILL_NIGHT_KILLER
&& KILL_ROLE(cu) != KILL_KILLER)
{
send_to_user(cu,"\033[1;35m$$ 很抱歉,目前只有殺手才能投票\033[0m",0,MSG_ME
SSAGE);
return;
}
if(cu->killflag & KILL_VOTED)
{
send_to_user(cu,"\033[1;35m$$ 抱歉啦,這次你已經投了一票了\033[0m",0,MSG_ME
SSAGE);
return;
}
if(xuser->killflag & KILL_KNOCKOUT)
{
send_to_user(cu,"\033[1;35m$$ 他已經是個死人了,你就行行好吧。\033[0m",0,MS
G_MESSAGE);
return;
}
/* esp: 既然大家都覺得晚上也應該可以殺殺手,那就殺 */
/*
if(room->killstatus == KILL_NIGHT_KILLER)
{
if(KILL_ROLE(xuser) == KILL_KILLER)
{
send_to_user(cu,"\033[1;35m$$ 不要殺害同類嗎。\033[0m",0,MSG_MESSAGE);
return;
}
}
*/
// esp: 殺手在白天可以投殺手的票嗎?我就讓他可以,這樣可能更隱蔽,KAKA
xuser->votenum ++;
cu->killflag |= KILL_VOTED;
if(room->killstatus != KILL_NIGHT_KILLER)
{
strcpy(cu->killid,xuser->chatid);
sprintf(buf,"\033[1;31m$$ 你投了 %s 一票!\033[0m",xuser->chatid);
send_to_user(cu,buf,0,MSG_MESSAGE);
// sprintf(buf,"\033[1;31m$$ %s 投了 %s 一票!\033[0m",cu->chatid,x
user->chatid);
// send_to_room(room,buf,0,MSG_MESSAGE,NULL);
}
else
{
sprintf(buf,"\033[1;31m$$ 你投了 %s 一票!\033[0m",xuser->chatid);
send_to_user(cu,buf,0,MSG_MESSAGE);
}
// kill_refresh_table(room);
kill_check_vote(room,cu);
}
#if 0
static void kill_user_vote(cu,msg)
ChatUser *cu;
char* msg;
{
char *twit, buf[80];
ChatUser *xuser;
ChatRoom *room;
if(room == ROOM_ALL || !(room->rflag & ROOM_KILLGAME))
{
send_to_user(cu,"$$ 這個房間不是遊戲房間",0,MSG_MESSAGE);
return;
}
if(!(room->rflag & ROOM_KILL_STARTED))
{
send_to_user(cu,"$$ 這個房間的遊戲還沒有開始",0,MSG_MESSAGE);
return;
}
if(room->killstatus != KILL_NIGHT_KILLER
&& room->killstatus != KILL_DAY_VOTE)
{
send_to_user(cu,"$$ 現在沒有舉辦投票",0,MSG_MESSAGE);
return ;
}
if(cu->killflag & KILL_KILLED)
{
send_to_user(cu,"$$ 抱歉啦,你現在無權投票",0,MSG_MESSAGE);
return;
}
if(KILL_ROLE(cu) == KILL_JUDGE)
{
send_to_user(cu,"$$ 抱歉啦,法官是不能投票的",0,MSG_MESSAGE);
return;
}
if(cu->killflag & KILL_VOTED)
{
send_to_user(cu,"$$ 抱歉啦,這次你已經投了一票了",0,MSG_MESSAGE);
return;
}
/* esp: 殺自己怎麼辦?? --回答是,才不管呢 */
twit = nextword(&msg);
xuser = cuser_by_chatid(twit);
if (xuser == NULL)
{ /* Thor.980604: 用 userid也嘛通 */
xuser = cuser_by_userid(twit);
}
if (xuser == NULL)
{
sprintf(buf, msg_no_such_id, twit);
send_to_user(cu, buf, 0, MSG_MESSAGE);
return;
}
room = cu->room;
if (room != xuser->room || CLOAK(xuser))
{
sprintf(buf, msg_not_here, twit);
send_to_user(cu, buf, 0, MSG_MESSAGE);
return;
}
if(room->killstatus == KILL_NIGHT_KILLER
&& KILL_ROLE(cu) != KILL_KILLER)
{
send_to_user(cu,"$$ 很抱歉,目前只有殺手才能投票",0,MSG_MESSAGE);
return;
}
xuser->votenum ++;
kill_refresh_table(room);
}
#endif
static void kill_refresh_table(room)
ChatRoom* room;
{
int c,line;
ChatUser *cu,*user;
char buf[384],buf2[128];
if(!room)
return ;
for(cu = mainuser;cu;cu = cu->unext)
{
if(!cu->userno)
continue;
if(cu->room != room)
continue;
line = 2;
sprintf(buf,"/u%d ",line);
for(c = 0,user = mainuser;user;user = user->unext)
{
if(!user->userno)
continue;
if(user->room != room)
continue;
if(room->killstatus == KILL_NOT_START)
sprintf(buf2,"%s%-12s%s%s",userkillstatecolors[user->killstate],user->c
hatid,"\033[0m",(c < 4 ? "│" : " "));
else
sprintf(buf2,"%s%s%-12s%s%s",userkillstatecolors[kill_get_user_state(ro
om,cu,user)],room->currenttalker == user?"\033[7m":"",user->chatid,"\033[0m",(c
< 4 ? "│" : " "));
strcat(buf,buf2);
if(++c == 5) // esp: I put 5 user per line, so i can more space
{
send_to_user(cu,buf,0,MSG_MESSAGE);
line ++;
c = 0;
sprintf(buf,"/u%d ",line);
}
}
if (c > 0) send_to_user(cu, buf, 0, MSG_MESSAGE);
}
}
static void kill_over(cu, msg)
ChatUser *cu;
char *msg;
{
ChatRoom *room;
room = cu->room;
if(room == ROOM_ALL || !(room->rflag & ROOM_KILLGAME))
{
send_to_user(cu,"\033[1;35m$$ 這個房間不是遊戲房間\033[0m",0,MSG_MESSAGE);
return;
}
if(!(room->rflag & ROOM_KILL_STARTED))
{
send_to_user(cu,"\033[1;35m$$ 這個房間的遊戲還沒有開始\033[0m",0,MSG_MESSAG
E);
return;
}
if(room->rflag & ROOM_KILL_WAITDROP)
{
send_to_user(cu,"\033[1;35m$$ 還是等等斷線的同志吧,多說會兒,多說兒會兒。\
033[0m",0,MSG_MESSAGE);
return;
}
if(room->killstatus == KILL_DAY_TALK
|| room->killstatus == KILL_DAY_MURDERED
|| room->killstatus == KILL_BEFORENIGHT
&& room->currenttalker == cu
)
{
kill_talk_over(room,cu);
}
else
{
send_to_user(cu,"\033[1;35m$$ 您現在根本就什麼都沒幹\033[0m",0,MSG_MESSAGE)
;
}
return;
}
#if 0
static void kill_killer_over(room,cu)
ChatRoom *room;
ChatUser *cu;
{
if(cu->killflag & KILL_KNOCKOUT)
{
send_to_user(cu,"\033[1;35m$$ 你的魂靈還沒有回到身體裡呢\033[0m",0,MSG_MESS
AGE);
return;
}
if(cu->killflag & KILL_TALKED)
{
send_to_user(cu,"\033[1;35m$$ 你已經結束晚上的活動了\033[0m",0,MSG_MESSAGE)
;
return;
}
cu->killflag |= KILL_TALKED;
kill_on_user_over(room);
}
static void kill_police_over(room,cu)
ChatRoom *room;
ChatUser *cu;
{
if(cu->killflag & KILL_KNOCKOUT)
{
send_to_user(cu,"\033[1;35m$$ 你的魂靈還沒有回到身體裡呢\033[0m",0,MSG_MESS
AGE);
return;
}
if(cu->killflag & KILL_TALKED)
{
send_to_user(cu,"\033[1;35m$$ 你已經結束晚上的活動了\033[0m",0,MSG_MESSAGE)
;
return;
}
cu->killflag |= KILL_TALKED;
kill_on_user_over(room);
}
#endif
static void kill_talk_over(room,cu)
ChatRoom *room;
ChatUser *cu;
{
ChatUser *user;
char buf[128];
if(cu->killflag & KILL_KNOCKOUT)
{
send_to_user(cu,"\033[1;35m$$ 你的魂靈還沒有回到身體裡呢\033[0m",0,MSG_MESS
AGE);
return;
}
if(cu->killflag & KILL_TALKED)
{
send_to_user(cu,"\033[1;35m$$ 你已經結束發言了\033[0m",0,MSG_MESSAGE);
return;
}
if(cu != room->currenttalker)
{
send_to_user(cu,"\033[1;35m$$ 你根本就沒有在發言\033[0m",0,MSG_MESSAGE);
return;
}
sprintf(buf,"\033[1;33m$$ %s 的發言已經結束了\033[0m",cu->chatid);
send_to_room(room,buf,0,MSG_MESSAGE,NULL);
cu->killflag |= KILL_TALKED;
if(!kill_on_user_over(room))
{
user = kill_get_next_user(room,cu);
room->currenttalker = user;
user->tkillbegin = time(0);
sprintf(buf,"\033[1;33m$$ 現在由 %s 發言\033[0m",user->chatid);
send_to_room(room,buf,0,MSG_MESSAGE,NULL);
kill_refresh_table(room);
}
}
static int kill_on_user_over(room)
ChatRoom *room;
{
ChatUser *user;
int count = 0;
for(user = mainuser;user;user = user->unext)
{
if(!user->userno)
continue;
if(user->room != room)
continue;
if(room->killstatus == KILL_DAY_MURDERED)
{
kill_next_status(room,NULL);
return 1;
}
if(room->killstatus == KILL_BEFORENIGHT)
{
kill_next_status(room,NULL);
return 1;
}
else if(room->killstatus == KILL_DAY_TALK)
{
if(user->killflag & KILL_TALKED || user->killflag & KILL_KNOCKOUT)
{
count ++;
if(count == room->policenum + room->normalnum + room->killernum)
{
kill_next_status(room,NULL);
return 1;
}
}
}
}
return 0;
}
static ChatUser *kill_get_next_user(room,cu)
ChatRoom *room;
ChatUser *cu;
{
ChatUser *user,*prevuser;
if(!room)
return NULL;
prevuser = NULL;
for(user = mainuser;user;user = user->unext)
{
if(!user->userno)
continue;
if(user->room != room)
continue;
if(room->killstatus == KILL_DAY_TALK)
{
if(!(user->killflag & KILL_KNOCKOUT))
{
if(prevuser == cu)
return user;
prevuser = user;
}
}
}
return NULL;
}
static void kill_check_vote(room,cu)
ChatRoom* room;
ChatUser* cu;
{
int max = 0, count = 0;
ChatUser *user,*maxuser = NULL;
char buf[128];
for(user = mainuser;user;user = user->unext)
{
if(user->room != room)
continue;
if(room->killstatus == KILL_NIGHT_KILLER)
{
if(KILL_ROLE(user) == KILL_KILLER && !(user->killflag & KILL_KNOCKOUT)
&& !(user->killflag & KILL_VOTED))
return ;
}
else if(room->killstatus == KILL_DAY_VOTE)
{
if(!(user->killflag & KILL_KILLED)
&& !(user->killflag & KILL_VOTED))
{
return ;
}
}
else
return;
}
for(user = mainuser;user;user = user->unext)
{
if(user->room != room)
continue;
if(user->killflag & (KILL_KNOCKOUT | KILL_KILLED))
continue;
/* esp: zk told me to show the vote detail together */
if(room->killstatus == KILL_DAY_VOTE)
{
sprintf(buf,"\033[1;31m$$ %s 投了 %s 一票!\033[0m",user->chatid,
user->killid);
send_to_room(room,buf,0,MSG_MESSAGE,NULL);
}
if(user->votenum > max)
{
maxuser = user;
max = user->votenum;
count = 1;
}
else if(user->votenum == max)
{
count ++;
}
}
if(count != 1)
{
kill_clear_user_vote(room);
kill_enable_user_vote(room);
// kill_refresh_table(room);
if(room->killstatus == KILL_NIGHT_KILLER)
send_to_room(room,"\033[1;35m$$ 有并列第一的,現在大家重新投票吧\033[0m",
0,MSG_MESSAGE,cu);
else
send_to_room(room,"\033[1;35m$$ 有并列第一的,現在大家重新投票吧\033[0m",
0,MSG_MESSAGE,NULL);
return;
}
user = maxuser;
user->killflag |= KILL_KILLED;
if(room->killstatus == KILL_NIGHT_KILLER)
{
if(KILL_ROLE(user) == KILL_KILLER)
user->killstate = KILL_USER_KILLED_KILLER;
else if(KILL_ROLE(user) == KILL_POLICE)
user->killstate = KILL_USER_KILLED_POLICE;
else if(KILL_ROLE(user) == KILL_NORMAL)
user->killstate = KILL_USER_KILLED_NORMAL;
}
else
{
// esp: should be KILL_DAY_VOTE
if(KILL_ROLE(user) == KILL_KILLER)
user->killstate = KILL_USER_KILLED_KILLER;
else if(KILL_ROLE(user) == KILL_POLICE)
user->killstate = KILL_USER_MISKILLED_POLICE;
else if(KILL_ROLE(user) == KILL_NORMAL)
user->killstate = KILL_USER_MISKILLED_NORMAL;
}
kill_next_status(room,NULL);
}
static void kill_on_reconnect(room)
ChatRoom* room;
{
ChatUser *user;
for(user = mainuser;user;user = user->unext)
{
if(user->room != room)
continue;
if(user->killflag & KILL_DROPED)
return;
}
room->rflag &= ~ROOM_KILL_WAITDROP;
}
static void kill_parse_start_options(room,msg)
ChatRoom *room;
char* msg;
{
int police = 0,nopolice = 0,discuss = 0,noghost = 0;
int strpolice = 0;
char *str;
if(!msg)
return ;
str = nextword(&msg);
while(str && *str)
{
if(!strcmp(str,"police"))
police = 1;
else if(!strcmp(str,"nopolice"))
nopolice = 1;
else if(!strcmp(str,"discuss"))
discuss = 1;
else if(!strcmp(str,"noghost"))
noghost = 1;
else if(!strcmp(str,"strpolice"))
strpolice = 1;
str = nextword(&msg);
}
if(police == 1)
room->rflag |= ROOM_KILL_POLICE;
if(nopolice == 1)
room->rflag |= ROOM_KILL_NOPOLICE;
if(discuss == 1)
room->rflag |= ROOM_KILL_DISCUSS;
if(noghost == 1)
room->rflag |= ROOM_KILL_NOGHOST;
if(strpolice == 1)
room->rflag |= ROOM_KILL_STRPOLICE;
}
static void kill_police_query(cu, msg)
ChatUser *cu;
char *msg;
{
ChatRoom *room;
char *twit,buf[80];
ChatUser *xuser;
room = cu->room;
if(room == ROOM_ALL || !(room->rflag & ROOM_KILLGAME))
{
send_to_user(cu,"\033[1;35m$$ 這個房間不是遊戲房間\033[0m",0,MSG_MESSAGE);
return;
}
if(!(room->rflag & ROOM_KILL_STARTED))
{
send_to_user(cu,"\033[1;35m$$ 這個房間的遊戲還沒有開始\033[0m",0,MSG_MESSAG
E);
return;
}
if(cu->killflag & KILL_KILLED)
{
send_to_user(cu,"\033[1;35m$$ 死人就不能再查詢別人了:(\033[0m",0,MSG_MESSAG
E);
return;
}
twit = nextword(&msg);
xuser = cuser_by_chatid(twit);
if(xuser == NULL)
{
xuser = cuser_by_userid(twit);
}
if(xuser == NULL || xuser->room != room)
{
sprintf(buf, msg_no_such_id, twit);
send_to_user(cu, buf, 0, MSG_MESSAGE);
return;
}
if(KILL_ROLE(cu) != KILL_POLICE)
{
send_to_user(cu,"\033[1;35m$$ 只有警察才能查詢別人\033[0m",0,MSG_MESSAGE);
return;
}
if(room->rflag & ROOM_KILL_STRPOLICE)
{
send_to_user(cu,"\033[1;35m$$ 不必查詢,你會慢慢知道的\033[0m",0,MSG_MESSAG
E);
return;
}
if(cu->killflag & KILL_QUERYED)
{
send_to_user(cu,"\033[1;35m$$ 抱歉啦,今天你已經查詢過了\033[0m",0,MSG_MESS
AGE);
return;
}
xuser->killflag |= KILL_QUERYED ;
cu->killflag |= KILL_QUERYED;
sprintf(buf,"\033[1;31m$$ %s 的身份是 %s%s%s!\033[0m",
xuser->chatid, userkillstatecolors[xuser->killstate],
userkillstates[xuser->killstate],"\033[0m");
send_to_user(cu,buf,0,MSG_MESSAGE);
}
static void kill_show_next_killer(room)
ChatRoom *room;
{
ChatUser * user;
for(user = mainuser;user;user = user->unext)
{
if(!user->userno)
continue;
if(user->room != room)
continue;
if(KILL_ROLE(user)==KILL_KILLER && !(user->killflag & KILL_QUERYED)) {
user->killflag |= KILL_QUERYED;
return;
}
}
}
static void kill_talk_time_check(room)
ChatRoom *room;
{
int timelimit; // in seconds
if(!(room->rflag & ROOM_KILL_STARTED))
return;
if(NULL == room->currenttalker)
return;
if(room->killstatus == KILL_DAY_MURDERED
|| room->killstatus == KILL_BEFORENIGHT)
timelimit = 60;
else if(room->killstatus == KILL_DAY_TALK)
timelimit = 45;
else
return;
if(time(0) - room->currenttalker->tkillbegin > timelimit)
kill_talk_over(room,room->currenttalker);
return;
}
static void kill_vote_time_check(room)
ChatRoom *room;
{
int timelimit = 30;
if(!(room->rflag & ROOM_KILL_STARTED))
return;
if(room->killstatus != KILL_NIGHT_KILLER
&& room->killstatus != KILL_DAY_VOTE)
return;
if(room->killstatus == KILL_NIGHT_KILLER)
timelimit = 60;
if(time(0) - room->tvotebegin > timelimit)
{
kill_auto_vote(room);
}
return;
}
static ChatUser*
kill_auto_vote(room)
ChatRoom *room;
{
int max = 0, count = 0;
int r,total = 0;
ChatUser *user,*maxuser = NULL;
char buf[128];
for(user = mainuser;user;user = user->unext)
{
if(user->room != room)
continue;
if(user->killflag & (KILL_KNOCKOUT | KILL_KILLED))
continue;
if(user->votenum > max)
{
maxuser = user;
max = user->votenum;
count = 1;
}
else if(user->votenum == max && max != 0)
{
count ++;
}
}
if(count == 0)
{
// nobody voted
total = room->policenum + room->killernum + room->normalnum;
srand(time(0));
r = (float) rand() / RAND_MAX * total;
do {
user = chat_get_nth_user(room,r+1);
r = (r + 1) % total;
} while( user->killflag & KILL_KILLED);
// now , the 'user' should be the poor guy.
}
else if(count != 1)
{
// more than one elected, we random one out
srand(time(0));
total = room->policenum + room->killernum + room->normalnum;
r = (float) rand() / RAND_MAX * count;
count = 0;
for(user = mainuser;user;user=user->unext)
{
if(user->room != room)
continue;
if(user->userno == 0)
continue;
if(user->killflag & KILL_KILLED)
continue;
if(user->votenum != max)
continue;
count ++;
if(count >= r+1)
break;
}
}
else
{
user = maxuser;
}
maxuser = user;
for(user = mainuser;user;user=user->unext)
{
if(user->room != room)
continue;
if(user->userno == 0)
continue;
if(user->killflag & KILL_KILLED)
continue;
if(room->killstatus == KILL_NIGHT_KILLER)
if(KILL_ROLE(user) != KILL_KILLER)
continue;
if(!(user->killflag & KILL_VOTED))
{
maxuser->votenum ++;
user->killflag |= KILL_VOTED;
if(room->killstatus != KILL_NIGHT_KILLER)
{
strcpy(user->killid,maxuser->chatid);
sprintf(buf,"\033[1;31m$$ 你投了 %s 一票!\033[0m",maxuser->
chatid);
send_to_user(user,buf,0,MSG_MESSAGE);
}
else
{
sprintf(buf,"\033[1;31m$$ 你投了 %s 一票!\033[0m",maxuser->
chatid);
send_to_user(user,buf,0,MSG_MESSAGE);
}
kill_check_vote(room,user);
}
}
}
static void kill_kkk(cu,msg)
ChatUser *cu;
char* msg;
{
ChatRoom *room;
room = cu->room;
if(room == ROOM_ALL || !(room->rflag & ROOM_KILLGAME))
{
send_to_user(cu,"\033[1;35m$$ 這個房間不是遊戲房間\033[0m",0,MSG_MESSAGE);
return;
}
if(!(room->rflag & ROOM_KILL_STARTED))
{
send_to_user(cu,"\033[1;35m$$ 這個房間的遊戲還沒有開始\033[0m",0,MSG_MESSAGE);
return;
}
kill_talk_time_check(room);
kill_vote_time_check(room);
}
static void kill_log_state(user, nmode)
ChatUser *user;
int nmode;
{
char fpath[80];
FILE *fp;
KILL_STATE killstate;
memset(&killstate,0,sizeof(KILL_STATE));
usr_fpath(fpath,user->userid,".KILLGAME");
fp = fopen(fpath,"rb");
if(NULL != fp)
{
fread(&killstate,sizeof(KILL_STATE),1,fp);
fclose(fp);
}
switch(nmode)
{
case 1:
killstate.won ++;
break;
case 2:
killstate.lost ++;
break;
case 3:
killstate.dropped ++;
break;
default:
break;
}
killstate.lastgame = nmode;
killstate.tlastgame = time(0);
fp = fopen(fpath,"wb+");
if(NULL != fp)
{
fwrite(&killstate,sizeof(KILL_STATE),1,fp);
fclose(fp);
}
}
static void
kill_show_state(cu, msg)
ChatUser *cu;
char *msg;
{
char fpath[80], *twit;
FILE *fp;
KILL_STATE killstate;
struct stat st;
static char* gamedesc[4] = {
"","Won","Lost","Dropped"};
twit = nextword(&msg);
if(twit == NULL || *twit == 0)
twit = cu->userid;
usr_fpath(fpath,twit,FN_ACCT);
if(-1 == stat(fpath,&st))
{
send_to_user(cu,"\033[1;35m$$ 沒有這位使用者!\033[0m",0,MSG_MESSAGE);
return;
}
memset(&killstate,0,sizeof(KILL_STATE));
usr_fpath(fpath,twit,".KILLGAME");
fp = fopen(fpath,"rb");
if(NULL != fp)
{
fread(&killstate,sizeof(KILL_STATE),1,fp);
fclose(fp);
sprintf(fpath,"\033[1;33m$$ %s:\033[m",twit);
send_to_user(cu,fpath,0,MSG_MESSAGE);
sprintf(fpath,"\033[1;33m$$ Scores: %d-%d-%d\033[m",
killstate.won,killstate.lost,killstate.dropped);
send_to_user(cu,fpath,0,MSG_MESSAGE);
sprintf(fpath,"\033[1;33m$$ Lastgame: %s at %s\033[m",
gamedesc[killstate.lastgame],Btime(&(killstate.tlastgame)));
send_to_user(cu,fpath,0,MSG_MESSAGE);
}
else
{
send_to_user(cu,"\033[1;35m$$ 這位使用者沒有玩過遊戲\033[0m",0,MSG_MESSAGE);
}
return;
}
#endif /* HAVE_KILL_GAME */
--
□ □ □ □
□□□ □□□□□ □□□□□ □□□
□ □□ □□ □□ □□ □
□ □□ □□ □□ □□ □
□ □□ □□ □□ □□ □
□□□ □□□□□ □□□□□ □□□ ~~唉 呦呦~~~~~~
--
※ Origin: 【北郵真情流露】 <bupt.org> ◆ From: 202.112.254.105精華選讀←離開[主題上]主題下(k)上篇(j)下篇S/a搜尋 G串列 TAB精華 ↑↓捲 Pg/Space翻