/************************************************************************** * ___ __ __ ___ _ __ * * / _ \\ \/ // _ \ '_ \ * * | (_) |> <| __/ | | | * * \___//_/\_\\___|_| |_| * * * * 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.h" #include "card.h" #include "hand.h" #include #include #include #include #include #include #include #include #include "ui.h" #include "data_store.h" #include "net/comm.h" #include "net/client.h" #include "net/server.h" #include "game_states.h" #include "main_stack.h" /** * Game loop for clients. * Runs from game start to its end * @param[in] sock Socket with connection to server */ static void main_loop_client(int sock) { bool running = true; game_state_t state = STATE_CLIENT_WAIT_FOR_HAND_CARDS; uint8_t round = 0; while(running) { switch(state) { case STATE_CLIENT_WAIT_FOR_HAND_CARDS: round++; state = state_client_wait_for_hand_cards(sock, round); break; case STATE_CLIENT_SELECT_OPEN_CARD: state = state_client_select_open_card(sock); break; case STATE_CLIENT_WAIT_FOR_OPEN_CARDS: state = state_client_wait_for_open_cards(sock); break; case STATE_CLIENT_PLAY_CARDS: state = state_client_play_cards(sock); break; case STATE_CLIENT_GAME_FINISHED: // Game finished. No further state transition here state_client_game_finished(); running = false; break; default: printf("main_loop_client: entered unknown state\n"); exit(EXIT_FAILURE); } } } /** * Game loop for server. * Runs from game start to its end * @param[in] client_socks Sockets with connection to connected clients */ static void main_loop_server(socket_list_t* client_socks) { bool running = true; uint8_t round = 0; game_state_t state = STATE_SERVER_DEAL_HAND_CARDS; main_stack_t m; main_stack_init(&m); while(running) { switch(state) { case STATE_SERVER_DEAL_HAND_CARDS: round++; state = state_server_deal_hand_cards(client_socks, round, &m); break; case STATE_SERVER_WAIT_FOR_OPEN_CARDS: state = state_server_wait_for_open_cards(client_socks); break; case STATE_SERVER_PLAY_CARDS: state = state_server_play_cards(client_socks, &m); break; case STATE_SERVER_GAME_FINISHED: // Game finished. No further state transition here state_server_game_finished(); running = false; break; default: printf("main_loop_server: entered unknown state\n"); exit(EXIT_FAILURE); } } } /** * Prepares the start of a game. Clients connect to server and in servermode a server * is started which accepts connections * @param[in] servermode True if a server should be started to where the local client will connect * @param[in] addr Hostname/address where a client should try to connect (if NULL, default is "localhost"); in servermode address to which server will bind * @param[in] port Port to connect to / listen on * @param[in] num_players Only required on server; number of connections that are accepted before game is starting */ void start_game(const bool servermode, const char* addr, const char* port, const uint8_t num_players) { assert(port != NULL); // addr can be NULL for server -> listen on every address bool server_process = false; if(servermode) { pid_t child = fork(); server_process = (child == 0); // start server as child } if(server_process) // Start server and connect to localhost { int server_sock; socket_list_t client_socks; srand(time(0)); // Initialize RNG //srand(1337); // Constant debug RNG seed data_store_t *data = data_store(); server_sock = server_start(addr, port); server_get_players(server_sock, &client_socks, num_players); close(server_sock); // now no longer needed data->player_list.count = num_players; for(int i = 0; i < num_players; i++) { net_recv(client_socks.sockets[i], msg_type_hello_c); // assign ids (starting with 1; 0 is invalid) and notify clients of their ids client_socks.player_ids[i] = i+1; data->player_list.players[i].player_id = i+1; net_send(client_socks.sockets[i], msg_type_hello_s, &data->player_list.players[i]); } for(int i = 0; i < num_players; i++) { net_send(client_socks.sockets[i], msg_type_start_game, NULL); } main_loop_server(&client_socks); } else // Connect to server { int sock; if(addr == NULL) addr = "localhost"; for(int i=0; i<5; i++) // try to connect 5 times { sock = client_connect_server(addr, port); if(sock != -1) break; sleep(1); // wait one second before retry } if(sock == -1) { fprintf(stderr, "Connection refused\n"); exit(EXIT_FAILURE); } data_store_t *data = data_store(); net_send(sock, msg_type_hello_c, NULL); net_recv(sock, msg_type_hello_s); net_recv(sock, msg_type_start_game); ui_init(); // Display all windows ui_display_wnd_table_cards(&data->table_stacks, false, 0); ui_display_wnd_stack_points(&data->table_stacks, false, 0); ui_display_wnd_current_state(&data->player_list, data->player_list.count, false, 0, 0); ui_display_wnd_hand_cards(&data->hand, false, 0); main_loop_client(sock); ui_fini(); if(servermode) // wait until server (child) has exited wait(NULL); } destroy_data_store(); }