// pigroom.c 拱猪房

#include <pig.h>


inherit F_CLEAN_UP;
inherit ROOM;

int *specials = ({ 10, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 35, 47 });
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;
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),
	current_pig = 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);

void pig_init();
void bid_init();
void after_bid();
void round_init(string w);
void after_round();
void play_init();
void after_play();
void after_round();
void after_hand();

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

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

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 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;
	}
	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));
}
	
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");
}

string round_str()	// what happened in this round ?
{
	string r, cs; 
	int i;

	if (!objectp(pl[cs = round_order[roundcard_count]]))
		r = sprintf("现在轮到%s出：", chinese_seat[cs]);
	else
		r = sprintf("现在轮到%s出：", pl[cs]->query("name"));
	for (i = 0; i < roundcard_count; i++)
		r = sprintf("%s%s，", r, PIG_D->card_str(roundcards[round_order[i]]));
	return r + "\n";
}
string picks_str()
{
	int i;
        string r; 
        for (i = 0; i < 4; i++) {
		if (objectp(pl[seat[i]]))
                	r = pl[seat[i]]->query("name");
		else 
			r = chinese_seat[seat[i]];
                if (pick_count[seat[i]] > 0) {
                        r += "捡了下面这些牌：\n";
                        r += PIG_D->refresh(picks[seat[i]], 0, pick_count[seat[i]] - 1);
                }
                else
                        r = "";
        }
	return "捡牌情况：\n" + 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 (dir != "north" && dir != "west" && dir != "south" && dir != "east")
		dir == "north";
	if (pig_stage == PIG_PLAYING) { // 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";
		r = sprintf("%s现在是第%s轮\n", r, chinese_number(round_no));
		r += "卖了的牌：" + bidcard_str + "\n\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"));
		r += picks_str();
	}
	else {
	        r = "这是一张专门用于拱猪的四方桌。\n\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;
}

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

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

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

	map_delete(pl, (string)me->query_temp("pigging_seat"));
		
	if (!objectp(pl[arg])) {
		if (!sizeof(pl)) {
			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 (sizeof(pl) == 3)
			tell_room(this_object(), "现在是三缺一，你们只再需要一个玩家就可以开拱了。\n");
		if (sizeof(pl) == 4)
			tell_room(this_object(), "好，可以发牌了。桌长请用 deal 命令。\n");
		pig_stage = PIG_DEALING;
		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)
		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]], PIG_D->refresh(cards[seat[i]], 0, 12));
		card_count[seat[i]] = 13;
        }
	PIG_D->pig_announce("发完牌了，有谁要卖牌的没有？\n");
	PIG_D->pig_announce("如果你卖完了牌，打一下 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)
		return notify_fail("你手上没有牌。\n");
	write(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;
	PIG_D->pig_announce("全部停卖，开拱！！\n");
	PIG_D->pig_announce("这把由" + pl[dealer]->query("name") + "先出。\n");

	play_init();
	return 1;
}

void after_play()
{
	if (roundcard_count++ < 3) // still within a round
		tell_object(pl[round_order[roundcard_count]], 
			table_str(round_order[roundcard_count]));
	else
		after_round();
}
void after_round()
{
	string rw;

	// removes the 1st round bidcard play limit
		allow_playbid[SUIT(roundcards[round_order[0]])] = 1;
		// finds the winner of last round 
		rw = PIG_D->card_cmp4(roundcards, SUIT(roundcards[round_order[0]]));		
		message_vision("$N的" + PIG_D->card_str(roundcards[rw]) + "最大。\n", pl[rw]);
		// adds the special cards to the winner if any
		for (i = 0; i < 4; i++)
			for (j = 0; j < 16; j++)
				if (roundcards[seat[i]] == specials[j]) {
					picks[rw][pick_count[rw]++] = roundcards[seat[i]];	
					roundcards[seat[i]] == SPIG;
					dealer = seat[i];
				}
		// sort the picks array
		picks[rw] = sort_array(picks[rw], 1);
		// stuff we do after a hand is completed
		if (round_no++ == 13) {
			collect_all = "";
			for (i = 0; i < 4; i++) {
				current_pig[seat[i]] = 0;
				hscore[seat[i]] = PIG_D->count_score(picks[seat[i]], bid_flag);
				if (hscore[seat[i]] == 1000)
					collect_all = seat[i];
			}
			if (collect_all != "")
				for (i = 0; i < 4; i++) {
					tscore[seat[i]] += hscore[seat[i]];
					if (tscore[seat[i]] <= -1000) {
						pl[seat[i]]->add("pighead", 1);
						current_pig[seat[i]] = 1;
					}
				}
			else {
				for (i = 0; i < 4; i++)
					if (seat[i] != collect_all) {
						pl[seat[i]]->add("pighead", 1);
						current_pig[seat[i]] = 1;
					}
			}
			tell_object(this_object(), scoreboard_str());	
		}
		else
			round_init(rw);
	}
	else {
		tell_object(this_object(), round_str());
		tell_object(pl[round_order[roundcard_count]], 
			refresh_str(round_order[roundcard_count]));
	}
}
	
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]--;
	message_vision("$N出了一张" + PIG_D->card_str(c) + "。\n", me);
	after_play();
	return 1;
}
