/***************************************************************************** * ___ __ __ ___ _ __ * * / _ \\ \/ // _ \ '_ \ * * | (_) |> <| __/ | | | * * \___//_/\_\\___|_| |_| * * * * The card game * * * * Copyright (C) 2011, Reiner Herrmann * * Mario Kilies * * * * 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 . * * * *****************************************************************************/ #include "game_states.h" #include "net/comm.h" #include "ui.h" #include "data_store.h" #include /** * 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; iplayer_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); } if (!our_turn) { 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(); }