/* $Id$ */
#include "bbs.h"
// PTT-BBS Angel System
#ifdef PLAY_ANGEL
void
angel_toggle_pause()
{
if (!HasUserPerm(PERM_ANGEL) || !currutmp)
return;
currutmp->angelpause ++;
currutmp->angelpause %= ANGELPAUSE_MODES;
// maintain deprecated value
cuser.uflag2 &= ~UF2_ANGEL_OLDMASK;
}
void
angel_load_data()
{
// TODO cache angelmsg here.
}
int
t_changeangel(){
char buf[4];
/* cuser.myangel == "-" means banned for calling angel */
if (cuser.myangel[0] == '-' || cuser.myangel[1] == 0) return 0;
getdata(b_lines - 1, 0,
"更換小天使後就無法換回了喔! 是否要更換小天使? [y/N]",
buf, 3, LCECHO);
if (buf[0] == 'y' || buf[0] == 'Y') {
char buf[100];
snprintf(buf, sizeof(buf), "%s小主人 %s 換掉 %s 小天使\n",
ctime4(&now), cuser.userid, cuser.myangel);
buf[24] = ' '; // replace '\n'
log_file(BBSHOME "/log/changeangel.log", LOG_CREAT, buf);
cuser.myangel[0] = 0;
outs("小天使更新完成,下次呼叫時會選出新的小天使");
}
return XEASY;
}
int
t_angelmsg(){
char msg[3][74] = { "", "", "" };
char nick[10] = "";
char buf[512];
int i;
FILE* fp;
setuserfile(buf, "angelmsg");
fp = fopen(buf, "r");
if (fp) {
i = 0;
if (fgets(msg[0], sizeof(msg[0]), fp)) {
chomp(msg[0]);
if (strncmp(msg[0], "%%[", 3) == 0) {
strlcpy(nick, msg[0] + 3, 7);
move(4, 0);
prints("原有暱稱:%s小天使", nick);
msg[0][0] = 0;
} else
i = 1;
} else
msg[0][0] = 0;
move(5, 0);
outs("原有留言:\n");
if(msg[0][0])
outs(msg[0]);
for (; i < 3; ++i) {
if(fgets(msg[i], sizeof(msg[0]), fp)) {
outs(msg[i]);
chomp(msg[i]);
} else
break;
}
fclose(fp);
}
getdata_buf(11, 0, "小天使暱稱:", nick, 7, 1);
do {
move(12, 0);
clrtobot();
outs("不在的時候要跟小主人說什麼呢?"
"最多三行,按[Enter]結束");
for (i = 0; i < 3 &&
getdata_buf(14 + i, 0, ":", msg[i], sizeof(msg[i]), DOECHO);
++i);
getdata(b_lines - 2, 0, "(S)儲存 (E)重新來過 (Q)取消?[S]",
buf, 4, LCECHO);
} while (buf[0] == 'E' || buf[0] == 'e');
if (buf[0] == 'Q' || buf[0] == 'q')
return 0;
setuserfile(buf, "angelmsg");
if (msg[0][0] == 0)
unlink(buf);
else {
FILE* fp = fopen(buf, "w");
if(nick[0])
fprintf(fp, "%%%%[%s\n", nick);
for (i = 0; i < 3 && msg[i][0]; ++i) {
fputs(msg[i], fp);
fputc('\n', fp);
}
fclose(fp);
}
return 0;
}
inline int
angel_reject_me(userinfo_t * uin){
int* iter = uin->reject;
int unum;
while ((unum = *iter++)) {
if (unum == currutmp->uid) {
return 1;
}
}
return 0;
}
static int
FindAngel(void){
int nAngel;
int i, j;
int choose;
int trial = 0;
userinfo_t *u;
do{
nAngel = 0;
// since we have many, many angels now, let's ignore angels in angelpause state.
j = SHM->currsorted;
u = NULL;
for (i = 0; i < SHM->UTMPnumber; ++i)
{
u = &SHM->uinfo[SHM->sorted[j][0][i]];
if ((u->userlevel & PERM_ANGEL) && (!u->angelpause) && (u->mode != DEBUGSLEEPING))
++nAngel;
}
if (nAngel == 0)
return 0;
choose = random() % nAngel + 1;
j = SHM->currsorted;
for (i = 0; i < SHM->UTMPnumber && choose; ++i)
{
u = &SHM->uinfo[SHM->sorted[j][0][i]];
if ((u->userlevel & PERM_ANGEL) && (!u->angelpause) && (u->mode != DEBUGSLEEPING))
--choose;
}
// u should be correct now! No need to check angelpause in this time.
// u = &(SHM->uinfo[SHM->sorted[j][0][i-1]]);
if (choose == 0 && u &&
(u->uid != currutmp->uid) &&
(u->userlevel & PERM_ANGEL) &&
!angel_reject_me(u) &&
u->userid[0]){
strlcpy(cuser.myangel, u->userid, sizeof(cuser.myangel));
passwd_update(usernum, &cuser);
return 1;
}
}while(++trial < 5);
return 0;
}
static inline void
GotoNewHand(){
char old_board[IDLEN + 1] = "";
int canRead = 1;
if (currutmp && currutmp->mode == EDITING)
return;
// usually crashed as 'assert(currbid == brc_currbid)'
if (currboard[0]) {
strlcpy(old_board, currboard, IDLEN + 1);
currboard = "";// force enter_board
}
if (enter_board(BN_NEWBIE) == 0)
canRead = 1;
if (canRead)
Read();
if (canRead && old_board[0])
enter_board(old_board);
}
static inline void
NoAngelFound(const char* msg){
move(b_lines, 0);
outs(msg);
if (currutmp == NULL || currutmp->mode != EDITING)
outs(",請先在新手板上尋找答案或按 Ctrl-P 發問");
clrtoeol();
refresh();
sleep(1);
GotoNewHand();
return;
}
static inline void
AngelNotOnline(){
char buf[PATHLEN] = "";
const static char* const not_online_message = "您的小天使現在不在線上";
// TODO cache angel's nick name!
if (cuser.myangel[0] != '-')
sethomefile(buf, cuser.myangel, "angelmsg");
if (cuser.myangel[0] == '-' || !dashf(buf))
NoAngelFound(not_online_message);
else {
time4_t mod = dasht(buf);
FILE* fp = fopen(buf, "r");
clear();
showtitle("小天使留言", BBSNAME);
move(4, 0);
buf[0] = 0;
fgets(buf, sizeof(buf), fp);
if (strncmp(buf, "%%[", 3) == 0) {
chomp(buf);
prints("您的%s小天使現在不在線上", buf + 3);
fgets(buf, sizeof(buf), fp);
} else
outs(not_online_message);
outs("\n祂留言給你:\n");
outs(ANSI_COLOR(1;31;44) "⊙┬──────────────┤" ANSI_COLOR(37) ""
"小天使留言" ANSI_COLOR(31) "├──────────────┬⊙" ANSI_RESET "\n");
outs(ANSI_COLOR(1;31) "╭┤" ANSI_COLOR(32) " 小天使 "
" " ANSI_COLOR(31) "├╮" ANSI_RESET "\n");
do {
chomp(buf);
prints(ANSI_COLOR(1;31) "│" ANSI_RESET "%-74.74s" ANSI_COLOR(1;31) "│" ANSI_RESET "\n", buf);
} while (fgets(buf, sizeof(buf), fp));
outs(ANSI_COLOR(1;31) "╰┬──────────────────────"
"─────────────┬╯" ANSI_RESET "\n");
outs(ANSI_COLOR(1;31;44) "⊙┴─────────────────────"
"──────────────┴⊙" ANSI_RESET "\n");
prints("%55s%s", "留言日期: ", Cdatelite(&mod));
move(b_lines - 4, 0);
outs("小主人使用上問題找不到小天使請到新手版(" BN_NEWBIE ")\n"
" 想留言給小天使請到許\願版(AngelPray)\n"
" 想找看板在哪的話可到(AskBoard)\n"
"請先在各板上尋找答案或按 Ctrl-P 發問");
pressanykey();
GotoNewHand();
}
}
static void
TalkToAngel(){
static int AngelPermChecked = 0;
userinfo_t* uent;
userec_t xuser;
if (strcmp(cuser.myangel, "-") == 0){
AngelNotOnline();
return;
}
if (cuser.myangel[0] && !AngelPermChecked) {
getuser(cuser.myangel, &xuser); // XXX if user doesn't exist
if (!(xuser.userlevel & PERM_ANGEL))
cuser.myangel[0] = 0;
}
AngelPermChecked = 1;
if (cuser.myangel[0] == 0 && ! FindAngel()){
NoAngelFound("現在沒有小天使在線上");
return;
}
uent = search_ulist_userid(cuser.myangel);
if (uent == 0 || uent->angelpause || angel_reject_me(uent)){
AngelNotOnline();
return;
}
more("etc/angel_usage", NA);
/* 這段話或許可以在小天使回答問題時 show 出來
move(b_lines - 1, 0);
outs("現在你的id受到保密,回答你問題的小天使並不知道你是誰 \n"
"你可以選擇不向對方透露自己身份來保護自己 ");
*/
my_write(uent->pid, "問小天使: ", "小天使", WATERBALL_ANGEL, uent);
return;
}
void
CallAngel(){
static int entered = 0;
screen_backup_t old_screen;
if (!HasUserPerm(PERM_LOGINOK) || entered)
return;
entered = 1;
scr_dump(&old_screen);
TalkToAngel();
scr_restore(&old_screen);
entered = 0;
}
#endif // PLAY_ANGEL