// pigroom.c 拱猪房

#include <pig.h>


inherit ROOM;

string  *seat = ({ "north", "west", "south", "east" });
mapping chinese_seat = ([ 
        "north": "北边",
        "west" : "西边",
        "south": "南边",
        "east" : "东边",
]);

int pig_stage;
int round_no, roundcard_count;
string *round_order = allocate(4);
int bid_flag;
string bidcard_str = "";
object server;
string claimer;
mapping pl = allocate_mapping(4),
        cards = allocate_mapping(4),
        card_count = allocate_mapping(4),
        roundcards = allocate_mapping(4),
        picks = allocate_mapping(4),
        pick_count = allocate_mapping(4),
        passed = allocate_mapping(4),
        agreed = allocate_mapping(4),
        hscore = allocate_mapping(4),
        tscore = allocate_mapping(4);
        
string  dealer;
int     *allow_playbid = allocate(4);
int     *oldcards = allocate(52), 
        *newcards = allocate(52);

int pl_count();
void pig_init();
void deal_init();
void bid_init();
void after_bid();
void round_init(string w);
void after_round();
void play_init();
void after_claim();
void after_play();
void after_round();
void after_winner(string rw);
void after_hand();
void auto_play();

string refresh_str(string dir);
string picks_str();
string table_str(string dir);
string scoreboard_str();

void reset()    // set this room to no_reset
{}

int pl_count()
{
        int i, r;
        for (i = r = 0; i < 4; i++)
                if (objectp(pl[seat[i]]))
                        r++;
                else
                        map_delete(pl, seat[i]);
        return r;
}
void pig_init()
{
        int i;
        pig_stage = PIG_INITTING;
        for (i = 0; i < 4; i++) {
                tscore[seat[i]] = hscore[seat[i]] = 0;
                cards[seat[i]] = allocate(13);
                picks[seat[i]] = allocate(16);
        }
        for (i = 0; i < 52; i++)
                oldcards[i] = i;
}
void deal_init()
{
        pig_stage = PIG_DEALING;
        tell_room(this_object(), scoreboard_str());
        tell_room(this_object(),"桌长请 deal ！\n");
}
void bid_init()
{
        int i;
        pig_stage = PIG_BIDDING;
        bidcard_str = "";
        bid_flag = 0;
        for (i = 0; i < 4; i++) {
                allow_playbid[i] = 1;
                passed[seat[i]] = 0;
        }
}

void play_init()
{
        int i, j;
        pig_stage = PIG_PLAYING;
        round_no = 1;
        for (i = 0; i < 4; i++) {
                pick_count[seat[i]] = 0;
                card_count[seat[i]] = 13;
                for (j = 0; j < 16; j++)
                        picks[seat[i]][j] = 53;
                claimer = "";
                agreed[seat[i]] = 0;
        }
        round_init(dealer);
}
void round_init(string rw)
{
        int i;
        for (i = 0; i < 4; i++) 
                roundcards[seat[i]] = -1;
        roundcard_count = 0;
        round_order = PIG_D->order_turn(rw);
        if (pig_stage == PIG_PLAYING)
                tell_object(pl[rw], refresh_str(rw) + "现在轮到你出牌！\n");
}
        
void init()
{
        add_action("do_sit", "sit");
        add_action("do_leave", "leave");
        add_action("do_deal", "deal");
        add_action("do_bid", "bid");
        add_action("do_bid", "sell");
        add_action("do_pass", "pass");
        add_action("do_play", "play");
        add_action("do_refresh", "refresh");
        add_action("do_skip", "skip");
        add_action("do_claim", "claim");
        add_action("do_pigscore", "pigscore");
}

string picks_str()
{
        int i;
        string r = "", t; 
        for (i = 0; i < 4; i++) {
                t = "";
                if (objectp(pl[seat[i]]))
                        t = pl[seat[i]]->query("name");
                else 
                        t = chinese_seat[seat[i]];
                if (pick_count[seat[i]] > 0) {
                        t += "捡了下面这些牌：\n";
                        t += PIG_D->refresh(picks[seat[i]], 0, pick_count[seat[i]] - 1);
                }
                else
                        t = "";
                r += t;
        }
        return r;
}

string refresh_str(string dir)
{
//      if (dir != "north" && dir != "west" && dir != "south" && dir != "east")
                return PIG_D->refresh(cards[dir], 0, card_count[dir] - 1);
//      return "";
}
        

string table_str(string dir)    // what's going on in table ?
{
        int i;
        mapping rseat = ([]);
        string r = "", z = "";

        if (pig_stage == PIG_PLAYING && pl_count() == 4) { // if in playing mode
                if (dir != "north" && dir != "west" && dir != "south" 
                        && dir != "east")
                        rseat = PIG_D->order_turn("north");
                else
                        rseat = PIG_D->order_turn(dir);
//              r = "桌上面正在激烈的拱着！！\n";
        
                if (roundcard_count < 4)
                        r = sprintf("现在是第%s轮，该由%s出牌。\n", 
                        chinese_number(round_no), 
                        pl[round_order[roundcard_count]]->query("name"));
                if (bidcard_str != "")
                        r += "卖了的牌：" + bidcard_str + "\n\n";
                else
                        r += "没有人卖牌。\n";
                r = sprintf("%s%24s（%s）\n", r, "", pl[rseat[2]]->query("name"));      // writes north name
                r = sprintf("%s%26s%s\n", r, "", 
                        PIG_D->card_str(roundcards[rseat[2]]));
                r = sprintf("%s%4s%16s%6s%6s%6s%s\n", r, "", "（" + 
                        pl[rseat[3]]->query("name") + "）", 
                        PIG_D->card_str(roundcards[rseat[3]]), "", 
                        PIG_D->card_str(roundcards[rseat[1]]), "（" +
                        pl[rseat[1]]->query("name") + "）");
                r = sprintf("%s%26s%s\n", r, "",
                        PIG_D->card_str(roundcards[rseat[0]]));
                r = sprintf("%s%24s（%s）\n", r, "", pl[rseat[0]]->query("name"));
                if (card_count[dir] > 0)
                        r += refresh_str(dir);
                r += picks_str();
        }
        else {
                r = "这是一张专门用于拱猪的四方桌。\n\n";
                if (bidcard_str != "")
                        r += "卖了的牌：" + bidcard_str + "\n\n";
                else
                        r += "没有人卖牌。\n";
                for (i = 0; i < 4; i++) 
                        if (objectp(pl[seat[i]])) {
                                if (pl[seat[i]] == server) z = "@"; else z = "";
                                r = sprintf("%s%s的椅子上坐的是：%s(%s)%s。\n", r,
                                chinese_seat[seat[i]], pl[seat[i]]->query("name"),
                                pl[seat[i]]->query("id"), z);
                        }
                        else
                                r = sprintf("%s%4s的椅子是空的。如果你想玩，可以用 sit %-5s 坐上去。\n",
                                r, chinese_seat[seat[i]], seat[i]);
        }
        return r;
}

string scoreboard_str()
{
        int i;
        string r;
        r = "拱猪成绩表(Scoreboard)\n－－－－－－－－－－－－－－－－－\n姓名　　　　　　　　盘分　　　总分\n－－－－－－－－－－－－－－－－－\n";
        for (i = 0; i < 4; i++)
                if (objectp(pl[seat[i]]))
                        r = sprintf("%s%-14s%10d%10d\n", r,
                        (string)pl[seat[i]]->query("name"),
                        (int)hscore[seat[i]], (int)tscore[seat[i]]);
        return r + "－－－－－－－－－－－－－－－－－\n";
}

void score_reset()
{
        int i;
        for (i = 0; i < 4; i++) 
                tscore[seat[i]] = 0;
}

int do_skip(string arg)
{
        if (!this_player()->query_temp("pigging_seat"))
                return notify_fail("你没有在拱猪！\n");
        if (this_player() != server)
                return notify_fail("只有桌长才能跳过这副牌！\n");
        if (pig_stage < PIG_BIDDING)
                return notify_fail("牌都没有，跳什么？\n");
        message_vision("桌长$N决定跳过这副牌！！\n", server);
        if (pl_count() == 4)
                deal_init();
        return 1;
}

void after_claim()
{
        int i, j;
        for (i = 0; i < roundcard_count; i++) 
                if (PIG_D->is_special(roundcards[i]))
                        picks[claimer][pick_count[claimer]++] = roundcards[j];
        for (i = 0; i < 4; i++)
                for (j = 0; j < card_count[seat[i]]; j++)
                        if (PIG_D->is_special(cards[seat[i]][j]))
                                picks[claimer][pick_count[claimer]++] = cards[seat[i]][j];
        after_hand();
}

int do_claim(string arg)
{
        int i;
        object me = this_player();
        if (!me->query_temp("pigging_seat"))
                return notify_fail("你没有在拱猪！\n");
        if (pl_count() != 4)
                return notify_fail("现在桌子上没坐满！\n");
        if (pig_stage != PIG_PLAYING)
                return notify_fail("你想干什么？\n");
        if (claimer == me->query_temp("pigging_seat"))
                return notify_fail("一次就够了！\n");
        if (!arg) {
                if (claimer != "")
                        return notify_fail("claim yes|no ？\n");
                agreed[claimer = me->query_temp("pigging_seat")] = 1;
                write("你发出全收的要求！等待回音……\n");
                for (i = 0; i < 4; i++)
                        if (seat[i] != claimer)
                                tell_object(pl[seat[i]], me->query("name") + 
                                        "认为他手中的牌都是大的了！\n" +
                                        refresh_str(me->query_temp("pigging_seat")) +
                                        "请用 claim yes 通过，或者 claim no 否决。\n");
                return 1;
        }
        if (arg == "yes") {
                if (claimer == "")
                        return notify_fail("没有人想全收！\n");
                if (!agreed[me->query_temp("pigging_seat")]) {
                        agreed[me->query_temp("pigging_seat")] = 1;
                        message_vision("$N同意$n的牌都是大的了！\n", me, pl[claimer]);
                        for (i = 0; i < 4; i++)
                                if (agreed[seat[i]] != 1)
                                        return 1;
                        message_vision("$N的要求被通过了！！\n", pl[claimer]);
                        after_claim();
                        return 1;
                }
        }
        if (arg == "no") {
                if (claimer == "")
                        return notify_fail("没有人想全收！\n");
                message_vision("$N否决了$n的要求！！\n继续出牌！\n", me, pl[claimer]);
                claimer = "";
                for (i = 0; i < 4; i++)
                        agreed[seat[i]] = 0;
                return 1;
        }
        else
                return notify_fail("claim 什么？\n");
}

int do_sit(string arg)
{
        object me = this_player();

        if (!arg || (arg != "north" && arg != "west" && arg != "south" && arg != "east"))
                return notify_fail("你想坐在哪里？\n");

        if (server == me)
                return notify_fail("桌长不能换坐位！\n");

        map_delete(pl, (string)me->query_temp("pigging_seat"));
                
        if (!objectp(pl[arg])) {
                if (!pl_count()) {
                        pig_init();
                        server = me;
                        write("你现在是桌长！\n");
                        round_order = PIG_D->order_turn(dealer = arg);
                }
                pl[arg] = me;
                me->set_temp("pigging_seat", arg);
                message_vision("$N坐上了" + chinese_seat[arg] + "的位子。\n", me);
                if (pl_count() == 3)
                        tell_room(this_object(), "现在是三缺一，你们只再需要一个玩家就可以开拱了！\n");
                if (pl_count() == 4) {
                        tell_room(this_object(), "好，人凑齐了！\n");
                        deal_init();
                }
                return 1;
        }
        else
                return notify_fail("这个位子上已经有人了！\n");
}

int do_leave(string arg)
{
        int i;
        object me = this_player();

        if (!me->query_temp("pigging_seat", arg))
                return notify_fail("你现在没有在拱猪！\n");
        else if (server == me) {
                message_vision("桌长$N不想再拱下去了！\n", me);
                server = 0;
                for (i = 0; i < 4; i++) 
                        if (objectp(pl[seat[i]])) {
                                message_vision("$N站了起来。\n", pl[seat[i]]);
                                pl[seat[i]]->delete_temp("pigging_seat");
                                map_delete(pl, seat[i]);
                        }
                pig_stage = PIG_INITTING;
                return 1;
        }
        else {
                map_delete(pl, (string)me->query_temp("pigging_seat"));
                me->delete_temp("pigging_seat");
                message_vision("$N不想再拱了，站了起来！\n", me);
                return 1;
        }
}

void do_assign_cards()  // assign cards to players
{
        int i, j, k = 0;

        for (i = 0; i < 13; i++)
                for (j = 0; j < 4; j++) 
                        cards[seat[j]][i] = newcards[k++];
        for (i = 0; i < 4; i++) {
                cards[seat[i]] = sort_array(cards[seat[i]], 1);
                tell_object(pl[seat[i]], PIG_D->refresh(cards[seat[i]], 0, 12));
                card_count[seat[i]] = 13;
        }
}

int do_deal(string arg)
{
        int i, j, k;
        object me = this_player();
        if (me != server)
                return notify_fail("你不是桌长！\n");
        if (pig_stage != PIG_DEALING || pl_count() != 4)
                return notify_fail("现在不能发牌！\n");
        PIG_D->shuffle(oldcards, newcards, 2);

        for (i = 0; i < 13; i++)
                for (j = 0; j < 4; j++) 
                        cards[seat[j]][i] = newcards[k++];
        for (i = 0; i < 4; i++) {
                cards[seat[i]] = sort_array(cards[seat[i]], 1);
                tell_object(pl[seat[i]], "你得到的牌为：\n" +
                        PIG_D->refresh(cards[seat[i]], 0, 12));
                card_count[seat[i]] = 13;
        }
        tell_room(this_object(), "发完牌了，有谁要卖牌的没有？\n");
        tell_room(this_object(), "如果你卖完了牌，打一下 pass 。\n");
        bid_init();
        return 1;
}

int do_refresh(string arg)
{
        object me = this_player();
        if (!me->query_temp("pigging_seat"))
                return notify_fail("你没有在拱猪！\n");
        if (pig_stage < PIG_BIDDING || 
                card_count[me->query_temp("pigging_seat")] < 1)
                return notify_fail("你手上没有牌！\n");
        tell_object(pl[(string)me->query_temp("pigging_seat")], 
                "你手上有这些牌：\n" + refresh_str(me->query_temp("pigging_seat")));
        return 1;
}

int do_bid(string arg)
{
        object me = this_player();
        int c, b;
        string ts;

        if (!me->query_temp("pigging_seat"))
                return notify_fail("你没有在拱猪！\n");
        if (pig_stage != PIG_BIDDING)
                return notify_fail("现在不是卖牌的时候！\n");
        if (!arg)
                return notify_fail("你想卖什么？\n");
        if ((c = PIG_D->is_validcard(arg)) == -1 ||
                !PIG_D->has_card(cards[me->query_temp("pigging_seat")], 0, 12, c))
                return notify_fail("你手上没有这张牌！\n");
        if (!(b = PIG_D->is_validbid(c)))
                return notify_fail("这张牌不能被卖！\n");
        if (bid_flag & b)
                return notify_fail("这张牌已经被卖过了！\n");
        bid_flag |= b;
        switch (b) {
        case BID_SPIG :
                allow_playbid[0] = 0; break;
        case BID_HACE :
                allow_playbid[1] = 0; break;
        case BID_DSHEEP :
                allow_playbid[2] = 0; break;
        case BID_CTRANS :
                allow_playbid[3] = 0; break;
        }
        message_vision("$N说道：我卖" + PIG_D->card_str(c) + "！\n", me);
        ts = "";
        if (bidcard_str != "") ts = "，";
        bidcard_str = PIG_D->card_str(c) + "（" + me->query("name") + "）" +
                ts + bidcard_str;

        return 1;
}

int do_pass(string arg)
{
        object me = this_player();
        int i;

        if (!me->query_temp("pigging_seat"))
                return notify_fail("你没有在拱猪！\n");
        if (pig_stage != PIG_BIDDING)
                return notify_fail("你想干什么？\n");
        if (passed[me->query_temp("pigging_seat")] == 1)
                return notify_fail("你已经停卖了！\n");
        passed[me->query_temp("pigging_seat")] = 1;
        message_vision("$N说道：我停卖！\n", me);
        for (i = 0; i < 4; i++) 
                if ((int)passed[seat[i]] == 0)
                        return 1;

        for (i = 0; i < 4; i++)
                passed[seat[i]] = 0;
        tell_room(this_object(), "全部停卖，开拱！！\n");
        tell_room(this_object(), "这把由" + pl[dealer]->query("name") + "先出。\n");

        play_init();
        return 1;
}

void after_play()
{
        int i;
        roundcard_count++;
        for (i = 0; i < 4; i++) 
                if (card_count[seat[i]] > 0)
                        tell_object(pl[seat[i]], table_str(seat[i])); 
        if (roundcard_count > 3)
                after_round();
}
        
void after_winner(string rw)
{
        int i;
        message_vision("$N的" + PIG_D->card_str(roundcards[rw]) + "最大！\n", pl[rw]);
        for (i = 0; i < 4; i++)
                if (PIG_D->is_special(roundcards[seat[i]])) {
                        picks[rw][pick_count[rw]++] = 
                                roundcards[seat[i]];
                        if (roundcards[seat[i]] == SPIG) {
                                message_vision("$N得到了猪头！！\n", pl[rw]);
                                dealer = rw;
                        }
                }
        picks[rw] = sort_array(picks[rw], 1);
}

void after_round()
{
        string rw;

        allow_playbid[SUIT(roundcards[round_order[0]])] = 1;
        after_winner(rw = PIG_D->card_cmp4(roundcards, SUIT(roundcards[round_order[0]])));
        round_init(rw);
        
        if (round_no++ == 12) 
                auto_play();  // starts auto_play
}
void auto_play()
{
        int i;
        for (i = 0; i < 4; i++)
                roundcards[seat[i]] = cards[seat[i]][0];
        roundcard_count = 4;
        for (i = 0; i < 4; i++) {
                card_count[seat[i]] = 0;
                tell_object(pl[seat[i]], table_str(seat[i])); 
        }
        after_winner(PIG_D->card_cmp4(roundcards, SUIT(roundcards[round_order[0]])));
        after_hand();
}

void after_hand()
{
        // doing the scoring here
        int i, j, check_collect = 0;
        string collect_all = "";

        for (i = 0; i < 4; i++) {
                hscore[seat[i]] = PIG_D->count_score(picks[seat[i]], bid_flag);
                check_collect = check_collect + hscore[seat[i]];
                if (hscore[seat[i]] == 1000)
                        collect_all = seat[i];
                pl[seat[i]]->add("pig_new/played", 1);
                pl[seat[i]]->add("pig_new/score", hscore[seat[i]]);
        }
        if (collect_all == "" || check_collect != 1000)
                for (i = 0; i < 4; i++) {
                        tscore[seat[i]] += hscore[seat[i]];
                        if ( tscore[seat[i]] <= -1000
                        || tscore[seat[i]] >= 1000 ) {
                                pl[seat[i]]->add("pig_new/head", 1);
                                for (j = 0; j < 4; j++)
                                        if (j != i)     
                                        pl[seat[j]]->add("pig_new/pig_made", 1);
                        }
                }
        else
                for (i = 0; i < 4; i++)
                        if (seat[i] != collect_all) {
                                pl[seat[i]]->add("pig_new/head", 1);
                                message_vision("$N是一头猪！\n", pl[seat[i]]);
                        }
                        else
                                pl[seat[i]]->add("pig_new/pig_made", 3);
        for (i = 0; i < 4; i++) {
                if (tscore[seat[i]] <= -1000) {
                        message_vision("$N是一头猪！\n", pl[seat[i]]);
                        score_reset();
                        break;
                }
                else if (tscore[seat[i]] >= 1000) {
                        message_vision("$N是一头肥猪！\n", pl[seat[i]]);
                        score_reset();
                        break;
                }
                pl[seat[i]]->add("water", 20);
                pl[seat[i]]->add("food", 20);
        }
        deal_init();
}
        
int do_play(string arg)
{
        object me = this_player();
        int i, c, sc, nbc = 0, cpos = -1;
        string ms;

        if (!(ms = me->query_temp("pigging_seat")))
                return notify_fail("你没有在拱猪！\n");
        if (pig_stage != PIG_PLAYING)
                return notify_fail("现在不是出牌阶段！\n");
        if (ms != round_order[roundcard_count])
                return notify_fail("还没轮到你出牌！\n");
        if (!arg || (c = PIG_D->is_validcard(arg)) == -1)
                return notify_fail("你要出哪张牌？\n");
        for (i = 0; i < card_count[ms]; i++) 
                if (cards[ms][i] == c) {
                        cpos = i; break;
                }
        if (cpos == -1)
                return notify_fail("你手里没有这张牌！\n");

        if (roundcard_count > 0 && (sc = PIG_D->has_suit(cards[ms], 0, 
                card_count[ms] - 1, SUIT(roundcards[round_order[0]]))) > 0 && 
                SUIT(c) != SUIT(roundcards[round_order[0]]))
                return notify_fail("你不能出这张牌！\n");

        if (roundcard_count == 0 || sc > 1) {
                switch (c) {
                case SPIG :
                        if (!allow_playbid[SPADE])
                                nbc = 1;
                        break;
                case HACE :
                        if (!allow_playbid[HEART])
                                nbc = 1;
                        break;
                case DSHEEP : 
                        if (!allow_playbid[DIAMOND])
                                nbc = 1;
                        break;
                case CTRANS :
                        if (!allow_playbid[CLUB])
                                nbc = 1;
                        break;
                }
                if (nbc)
                        return notify_fail("卖过的牌不能在第一轮出！\n");
        }
        for (i = cpos; i < card_count[ms] - 1; i++)
                cards[ms][i] = cards[ms][i+1];
        cards[ms][13 - round_no] = 53;
        roundcards[ms] = c;
        card_count[ms]--;
        if (roundcard_count > 0 && SUIT(c) != SUIT(roundcards[round_order[0]]))
                message_vision("$N垫了一张" + PIG_D->card_str(c) + "！\n", me);
        else
                message_vision("$N出了一张" + PIG_D->card_str(c) + "！\n", me);
        after_play();
        return 1;
}


int do_pigscore()
{
    int pigplayed = (int)this_player()->query("pig_new/played");
    int pigmade = (int)this_player()->query("pig_new/pig_made");
    int pighead = (int)this_player()->query("pig_new/head");
    int score = (int)this_player()->query("pig_new/score");

    write("你拱过 " + pigplayed + " 盘猪，拱出 " 
        + pigmade + " 个猪头，你得了 " + pighead + " 个，总分 " + 
        score + " 。\n");
    return 1;
}
