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
|
#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();
}
|