summaryrefslogtreecommitdiff
path: root/src/client_game_states.c
blob: 21b0bb661d420c179c6dde494cbca1ff448b0c32 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/*****************************************************************************
 *                          ___ __  __ ___ _ __                              *
 *                         / _ \\ \/ // _ \ '_ \                             *
 *                        | (_) |>  <|  __/ | | |                            *
 *                         \___//_/\_\\___|_| |_|                            *
 *                                                                           *
 *                             The card game                                 *
 *                                                                           *
 *  Copyright (C) 2011, Reiner Herrmann <reiner@reiner-h.de>                 *
 *                      Mario Kilies <MarioKilies@GMX.net>                   *
 *                                                                           *
 *  This program is free software; you can redistribute it and/or modify     *
 *  it under the terms of the GNU General Public License as published by     *
 *  the Free Software Foundation; either version 3 of the License, or        *
 *  (at your option) any later version.                                      *
 *                                                                           *
 *  This program is distributed in the hope that it will be useful,          *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the             *
 *  GNU General Public License for more details.                             *
 *                                                                           *
 *  You should have received a copy of the GNU General Public License        *
 *  along with this program. If not, see <http://www.gnu.org/licenses/>.     *
 *                                                                           *
 *****************************************************************************/

#include "game_states.h"
#include "net/comm.h"
#include "ui.h"
#include "data_store.h"
#include <unistd.h>

/**
 * Game state handler. Handles the client, that waits for dealed hand cards from server. A message showing the waiting client is displayed. If it is the first round, the initial table stacks are received. The table stacks and stack points are displayed. The function blocks, until the initial stacks (only round 1) and the hand cards are received. On returning from the function, a state transition occurs.
 * @param[in] sock The server socket that is read from
 * @param[in] round Specifies the current round the game is in
 * @return STATE_CLIENT_SELECT_OPEN_CARD The next state after receiving hand cards
*/
game_state_t state_client_wait_for_hand_cards(const int sock, const uint8_t round)
{
	data_store_t *d = data_store();

	ui_display_wnd_messages("Waiting for hand cards from server", false);
	ui_update();

	if(round == 1)
	{
		// Receive and display table stacks
		net_recv(sock, msg_type_initial_stacks);
		ui_display_wnd_table_cards(&d->table_stacks, false, 0);
		ui_display_wnd_stack_points(&d->table_stacks, false, 0);
		ui_update();
	}

	// Wait for hand cards from server
	net_recv(sock, msg_type_deal_hand);

	return STATE_CLIENT_SELECT_OPEN_CARD;
}

/**
 * Game state handler. Handles the client, that has to pick an open card. The card chooser will be run and the selected card will be sent to the server. Afterwards, the selected card will be removed from the hand and the UI will update the hand cards. The function will block until the selected card is sent to the server. On returning from the function, a state transition occurs.
 * @param[in] sock The server socket that the selected card is sent to
 * @return STATE_CLIENT_WAIT_FOR_OPEN_CARDS The next state after choosing an open card
*/
game_state_t state_client_select_open_card(const int sock)
{
	data_store_t *d = data_store();
	uint8_t open_card_idx;

	// Select open card
	open_card_idx = ui_choose_card(&d->hand);
	d->selected_card = d->hand.cards[open_card_idx];

	// Send open card to server
	net_send(sock, msg_type_selected_card, NULL);

	// Remove picked open card from hand
	hand_remove_card(&d->hand, open_card_idx);
	ui_display_wnd_hand_cards(&d->hand, false, 0);
	ui_update();

	return STATE_CLIENT_WAIT_FOR_OPEN_CARDS;
}

/**
 * Game state handler. Handles the client, that waits for the open card list from server. Before receiving the open cards list, a message that the client is waiting for the other players is displayed. After receiving the list of open cards, the player list is sorted by the open cards in ascending order. On returning from the function, a state transition occurs.
 * @param[in] sock The server socket that is read from
 * @return STATE_CLIENT_PLAY_CARDS The next state after waiting for open card list
*/
game_state_t state_client_wait_for_open_cards(const int sock)
{
	data_store_t *d = data_store();

	ui_display_wnd_messages("Waiting for the other players to pick  their cards", false); // The two spaces between 'pick' and 'their' are intentionally and used for poor man's word wrap
	ui_update();

	net_recv(sock, msg_type_selected_card_all);
	player_list_sort_by_open_card(&d->player_list, d->player_list.count); // sort in ascending order

	player_list_entry_t *ple = get_player_list_entry_by_player_id(&d->player_list, d->own_player_id);
	assert(ple != NULL);

	return STATE_CLIENT_PLAY_CARDS;
}

/**
 * Game state handler. In this state, the client tries to play all received open cards. If a card is smaller than the stacks and it is the player's turn, display the stack selection window. If it is not the player's turn, receive another player's selected stack from the server. If a card from a player fits on a stack, but the stack is already full, then replace the stack with the card, and add the stack points to the player's points.
 * @param[in] sock The server socket that is read/written to
 * @return STATE_CLIENT_SELECT_OPEN_CARD The next state, if the player still has hand cards
 * @return STATE_CLIENT_WAIT_FOR_HAND_CARDS The next state, if the main stack is not empty. The server will deal us new hand cards
 * @return STATE_CLIENT_GAME_FINISHED The next state, if the main stack is empty
*/
game_state_t state_client_play_cards(const int sock)
{
	data_store_t *ds = data_store();
	player_list_entry_t *ple = get_player_list_entry_by_player_id(&ds->player_list, ds->own_player_id);
	assert(ple != NULL);

	for(int i=0; i<ds->player_list.count; i++)
	{
		card c = ds->player_list.players[i].open_card;
		uint8_t stack_idx = get_stack_idx_for_card(&ds->table_stacks, c);
		bool our_turn = (ds->player_list.players[i].player_id == ds->own_player_id);

		ui_display_wnd_messages("Placing cards ...", false);
		ui_display_wnd_current_state(&ds->player_list, ds->player_list.count, true, i, ple->score);
		ui_update();

		if(stack_idx >= NUM_TABLE_STACKS) // Card is smaller than any stack -> Stack has to be picked
		{
			if(our_turn) // our turn to select stack
			{
				ds->stack_index = ui_choose_stack(&ds->table_stacks);
				net_send(sock, msg_type_selected_stack_c, NULL);
			}

			ui_display_wnd_messages("Waiting for player to choose stack", false);
			ui_update();
			net_recv(sock, msg_type_selected_stack_s);
			ds->player_list.players[i].score += card_stack_get_points(&ds->table_stacks.stacks[ds->stack_index]);
			card_stack_replace(&ds->table_stacks.stacks[ds->stack_index], c);

			ui_display_wnd_table_cards(&ds->table_stacks, false, 0);
			ui_display_wnd_stack_points(&ds->table_stacks, false, 0);

			// If it was our turn, display the score
			if(our_turn)
			{
				ui_display_wnd_current_state(&ds->player_list, ds->player_list.count, true, i, ple->score);
			}
		}
		else // card fits on a stack -> place it
		{
			card_stack_t* cs = &ds->table_stacks.stacks[stack_idx];
			if(cs->cards[MAX_CARD_STACK_SIZE-1] != 0) // stack is full
			{
				ds->player_list.players[i].score += card_stack_get_points(cs);
				card_stack_replace(cs, c);

				// If it was our turn, display the score
				if(our_turn)
				{
					ui_display_wnd_current_state(&ds->player_list, ds->player_list.count, true, i, ple->score);
				}
			}
			else
				card_stack_push(cs, c);

			ui_display_wnd_table_cards(&ds->table_stacks, false, 0);
			ui_display_wnd_stack_points(&ds->table_stacks, false, 0);
		}

		ui_update();

		// Wait between player turns, but not after the last one
		if (i != ds->player_list.count - 1)
			sleep(2);
	}

	if(hand_count_cards(&ds->hand) > 0) // still cards in hand?
	{
		return STATE_CLIENT_SELECT_OPEN_CARD;
	}
	else
	{
		net_recv(sock, msg_type_next_action);
		if(!ds->game_finished) // no more cards -> server will deal
			return STATE_CLIENT_WAIT_FOR_HAND_CARDS;
		else
			return STATE_CLIENT_GAME_FINISHED;
	}

	assert(false);
	return 1337;
}

/**
 * Game state handler. Handles the client, after the game has finished. The player list will be sorted by score in ascending order and the final scores window will be displayed. As the game has finished, no state transition takes place before returning from this function.
*/
void state_client_game_finished(void)
{
	data_store_t *d = data_store();

	player_list_sort_by_score(&d->player_list, d->player_list.count); // Sort player list by scores in ascending ordner
	ui_display_wnd_final_scores(&d->player_list, d->player_list.count, d->own_player_id);
	ui_update();
}