diff --git a/README.md b/README.md index 500faf8..3d4852f 100644 --- a/README.md +++ b/README.md @@ -1 +1,10 @@ -# PR_Labirynt_Skarbow \ No newline at end of file +# PR Labirynt SkarbĂłw +Project for Distributed Processing course. +Multiplayer 2D game in real time. + +Written in C using: +* SDL2 library for graphic presentation +* Socket communication + +## Additional information +Developed in client-server architecture. diff --git a/additives.c b/additives.c new file mode 100644 index 0000000..effe601 --- /dev/null +++ b/additives.c @@ -0,0 +1,89 @@ +#include "additives.h" + +void read_BMP(char* filename, Map_type* map) +{ + FILE* f = fopen(filename, "rb"); + + if (f == NULL) + return; + + unsigned char info[54]; + fread(info, sizeof(unsigned char), 54, f); // read the 54-byte header + + // extract image height and width from header + map->size = *(int*)&info[18]; + + int row_padded = (map->size * 3 + 3) & (~3); + unsigned char** data = (char**)malloc(map->size * sizeof(unsigned char*)); + unsigned char* raw_pixel_data = (unsigned char*)malloc(row_padded * sizeof(unsigned char)); + + for (int i = map->size - 1; i >= 0; i--) + { + data[i] = (char*)malloc(map->size * sizeof(unsigned char)); + fread(raw_pixel_data, sizeof(unsigned char), row_padded, f); + for (int j = 0; j < map->size * 3; j += 3) + { + // Convert (B, G, R) to (R, G, B) + if (((int)raw_pixel_data[j] + (int)raw_pixel_data[j + 1] + (int)raw_pixel_data[j + 2]) / 3 < 128) + { + data[i][j / 3] = 0; + } + else + { + data[i][j / 3] = 1; + } + } + } + free(raw_pixel_data); + fclose(f); + map->labyrinth = data; +} + +void set_treasures(Map_type* map) +{ + int x_random, y_random; + for (int i = 0; i < NUMBER_OF_TREASURES; i++) + { + do + { + x_random = rand() % map->size; + y_random = rand() % map->size; + + } while (map->labyrinth[x_random][y_random] != FLOOR); + map->labyrinth[x_random][y_random] = TREASURE_OFFSET + i; + } +} + +void set_exit(Map_type* map) +{ + int x_random, y_random; + do + { + x_random = rand() % map->size; + y_random = rand() % map->size; + + } while (map->labyrinth[x_random][y_random] != FLOOR); + map->labyrinth[x_random][y_random] = EXIT; +} + +int find_best_player_index_excluding_arg_player(Map_type* map, int player) +{ + int best_score = -1; + int best_index = -1; + for (int i = 0; i < NUMBER_OF_CLIENTS; i++) + { + if (i == player) + { + continue; + } + if (map->players[i].connected && map->players[i].has_left == 0) + { + if (map->players[i].points > best_score) + { + best_index = i; + best_score = map->players[i].points; + } + } + } + return best_index; +} diff --git a/additives.h b/additives.h new file mode 100644 index 0000000..23ad1e5 --- /dev/null +++ b/additives.h @@ -0,0 +1,14 @@ +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include "../../../common/common_structures.h" + +void read_BMP(char* filename, Map_type* map); + +void set_treasures(Map_type* map); + +void set_exit(Map_type* map); + +int find_best_player_index_excluding_arg_player(Map_type* map, int player); diff --git a/client.c b/client.c index 04829c4..dd6c943 100644 --- a/client.c +++ b/client.c @@ -1,186 +1,347 @@ #define _CRT_SECURE_NO_WARNINGS - -#include #include #include #include #include - -#define LOCALHOST "127.0.0.1" -#define PORT 420 +#include "draw_functions.h" +#include "connection.h" +#include "players.h" #pragma comment(lib, "Ws2_32.lib") -void ping_server(const char* address) +int load_nickname(SDL_package_type package, char* nick) { - SOCKET s; - struct sockaddr_in sa; - WSADATA wsas; - WORD version; - int result; - char buf[30]; - version = MAKEWORD(2, 0); - WSAStartup(version, &wsas); - s = socket(AF_INET, SOCK_STREAM, 0); - memset((void*)(&sa), 0, sizeof(sa)); - sa.sin_family = AF_INET; - sa.sin_port = htons(PORT); - sa.sin_addr.s_addr = inet_addr(address); - int latency; - clock_t start, end; - result = connect(s, (struct sockaddr FAR*) & sa, sizeof(sa)); - if (result == SOCKET_ERROR) + SDL_bool done = SDL_FALSE; + SDL_Event event; + char text[128]; + char title[128]; + int position_x = 350; + int position_y = 100; + sprintf(title, "Labirynt skarbów"); + sprintf(text, "Podaj swoj nick: "); + sprintf(nick, "\0"); + int quit = 0; + while (!done && !quit) { - printf("Cannot connect to %s\n", address); + SDL_FillRect(package.screen, NULL, package.color); + draw_surface(&package, package.icon, position_x, position_y); + draw_text(title, position_x, position_y + 140, package); + draw_text(text, position_x, position_y + 220, package); + draw_text(nick, position_x, position_y + 260, package); + if (SDL_PollEvent(&event)) + { + switch (event.type) + { + case SDL_KEYDOWN: + if (event.key.keysym.sym == SDLK_RETURN) + { + done = SDL_TRUE; + } + break; + case SDL_TEXTINPUT: + strcat(nick, event.text.text); //wczytywanie nicku + break; + case SDL_QUIT: + quit = 1; + break; + } + } + SDL_UpdateTexture(package.texture, NULL, package.screen->pixels, package.screen->pitch); + SDL_RenderCopy(package.renderer, package.texture, NULL, NULL); + SDL_RenderPresent(package.renderer); } - else + return quit; +} + +int initialize_players(Buttons_type buttons, SOCKET server, Map_type* map, SDL_package_type package, int important_treasure, int* player_number) +{ + int position_x = 150; + int position_y = 120; + int latency; + SDL_Event event; + int ready = 0; + int everybody_ready = 0; + int quit = 0; + char treasure_name[20]; + while (everybody_ready != 1 && !quit) { - while (1) + SDL_FillRect(package.screen, NULL, package.color); + for (int i = 0; i < NUMBER_OF_CLIENTS; i++) { - strcpy(buf, "PING"); - send(s, buf, 30, 0); - start = clock(); - if (recv(s, buf, 30, 0) > 0) + package.foregroundColor = (SDL_Color){ 255, 0, 0 }; + if (map->players[i].connected == 1) { - end = clock(); - latency = (end - start) / (CLOCKS_PER_SEC / 1000); - buf[5] = '\0'; - printf("%s received after %d ms\n", buf, latency); + if (map->players[i].ready == 1) + { + package.foregroundColor = (SDL_Color){ 0, 255, 0 }; + } + draw_text(map->players[i].nick, position_x + 90 * i, position_y, package); } - else + } + sprintf(treasure_name, "Twoj skarb: %d", important_treasure); + draw_text(treasure_name, position_x + 200, position_y + 200, package); + package.foregroundColor = (SDL_Color){ 255, 255, 255 }; + while (SDL_PollEvent(&event)) + { + switch (event.type) { - printf("Ping lost\n"); + case SDL_KEYDOWN: + if (event.key.keysym.sym == buttons.action) + { + + if (ready == 0) + { + send_key_to_server(server, "ready"); + ready = 1; + } + else + { + send_key_to_server(server, "not_ready"); + ready = 0; + } + } + break; + case SDL_KEYUP: + break; + case SDL_QUIT: + quit = 1; + break; } - Sleep(2000); } + char dummy; + latency = ping_and_receive(server, map, &everybody_ready, player_number, &dummy); + SDL_UpdateTexture(package.texture, NULL, package.screen->pixels, package.screen->pitch); + SDL_RenderCopy(package.renderer, package.texture, NULL, NULL); + SDL_RenderPresent(package.renderer); } - closesocket(s); - WSACleanup(); + return quit; } -void send_key_to_server(const char* address, const char* key) +void draw_end_game(SDL_package_type* package, Map_type* map) { - SOCKET s; - struct sockaddr_in sa; - WSADATA wsas; - WORD version; - int result; - version = MAKEWORD(2, 0); - WSAStartup(version, &wsas); - s = socket(AF_INET, SOCK_STREAM, 0); - memset((void*)(&sa), 0, sizeof(sa)); - sa.sin_family = AF_INET; - sa.sin_port = htons(PORT); - sa.sin_addr.s_addr = inet_addr(address); - char buf[20]; - result = connect(s, (struct sockaddr FAR*) & sa, sizeof(sa)); - if (result == SOCKET_ERROR) + int quit = 0; + SDL_Event event; + for (int i = 0; i < NUMBER_OF_CLIENTS; i++) { - printf("Cannot connect to %s\n", address); + if (map->players[i].connected) + { + if (!map->players[i].has_left) + { + map->players[i].points /= 2; + } + } } - else + while (!quit) { - strcpy(buf, key); - send(s, buf, 20, 0); + draw_game_over(package, map); + while (SDL_PollEvent(&event)) + { + switch (event.type) + { + case SDL_KEYDOWN: + quit = 1; + break; + case SDL_QUIT: + quit = 1; + break; + } + } + SDL_UpdateTexture(package->texture, NULL, package->screen->pixels, package->screen->pitch); + SDL_RenderCopy(package->renderer, package->texture, NULL, NULL); + SDL_RenderPresent(package->renderer); } - closesocket(s); - WSACleanup(); } -int main(int argc, char** argv) +void start_game(Buttons_type buttons, SOCKET server, Map_type* map, SDL_package_type package, int player_number) { - TTF_Init(); - SDL_Window* win; - SDL_Renderer *renderer; - SDL_Texture* texture; - SDL_Surface* surface; - SDL_Color foregroundColor = { 255, 255, 255 }; - SDL_Color backgroundColor = { 0, 0, 255 }; - TTF_Font* font = TTF_OpenFont("fonts/Lato-Regular.ttf", 12); - SDL_Surface* text_surface; SDL_Event event; int is_running = 1; - // SDL_Color color={0,0,0}; - - if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { - printf("SDL init error! Code: %s\n", SDL_GetError()); - return 1; - } - win = SDL_CreateWindow("420", 400, 400, 640, 480, SDL_WINDOW_SHOWN ); - if (win == NULL) + int latency; + int dummy; + char game_over = 0; + while(is_running && game_over != 1) { - printf("Window creation error\n"); - SDL_Quit(); - return 1; + SDL_FillRect(package.screen, NULL, package.color); + draw_map(&package, map); + while (SDL_PollEvent(&event)) + { + switch (event.type) + { + case SDL_KEYDOWN: + + if(player_number != -1 && map->players[player_number].has_left != 1) + { + if (event.key.keysym.sym == buttons.up) + { + send_key_to_server(server, "up"); + } + else if (event.key.keysym.sym == buttons.down) + { + send_key_to_server(server, "down"); + } + else if (event.key.keysym.sym == buttons.right) + { + send_key_to_server(server, "right"); + } + else if (event.key.keysym.sym == buttons.left) + { + send_key_to_server(server, "left"); + } + else if(event.key.keysym.sym == buttons.action) + { + if (check_if_on_exit(map, player_number)) + { + send_key_to_server(server, "end_game"); + } + else + { + send_key_to_server(server, "skill"); + } + } + } + break; + case SDL_KEYUP: + break; + case SDL_QUIT: + is_running = 0; + break; + }; + }; + latency = ping_and_receive(server, map, &dummy, &dummy, &game_over); + SDL_UpdateTexture(package.texture, NULL, package.screen->pixels, package.screen->pitch); + SDL_RenderCopy(package.renderer, package.texture, NULL, NULL); + SDL_RenderPresent(package.renderer); } - renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); - if (renderer == NULL) +} + +Buttons_type set_buttons(SDL_package_type package) +{ + int position_x = 350; + int position_y = 100; + Buttons_type buttons = (Buttons_type){ 0, 0, 0, 0, 0 }; + SDL_Event event; + int choice = 1; + while (choice) { - SDL_DestroyWindow(win); - printf("Renderer creation error\n"); - SDL_Quit(); - return 1; + SDL_FillRect(package.screen, NULL, package.color); + draw_text("Wybierz sterowanie: ", position_x, position_y, package); + draw_text("1 - strzalki + prawy shift", position_x, position_y + POSITION_Y, package); + draw_text("2 - WSAD + E", position_x, position_y + 2*POSITION_Y, package); + draw_text("3 - IJKL + O", position_x, position_y + 3*POSITION_Y, package); + draw_text("4 - TFGH + Y", position_x, position_y + 4*POSITION_Y, package); + while (SDL_PollEvent(&event)) + { + switch (event.type) + { + case SDL_KEYDOWN: + if (event.key.keysym.sym == SDLK_1) + { //zestaw 1 - strzałki + buttons.up = SDLK_UP; + buttons.down = SDLK_DOWN; + buttons.right = SDLK_RIGHT; + buttons.left = SDLK_LEFT; + buttons.action = SDLK_RSHIFT; + choice = 0; + } + else if (event.key.keysym.sym == SDLK_2) + { //zestaw 2 - WSAD + buttons.up = SDLK_w; + buttons.down = SDLK_s; + buttons.right = SDLK_d; + buttons.left = SDLK_a; + buttons.action = SDLK_e; + choice = 0; + } + else if (event.key.keysym.sym == SDLK_3) + { //zestaw 3 - IJKL + buttons.up = SDLK_i; + buttons.down = SDLK_k; + buttons.right = SDLK_l; + buttons.left = SDLK_j; + buttons.action = SDLK_o; + choice = 0; + } + else if (event.key.keysym.sym == SDLK_4) + { //zestaw 4 - TFGH + buttons.up = SDLK_t; + buttons.down = SDLK_f; + buttons.right = SDLK_g; + buttons.left = SDLK_h; + buttons.action = SDLK_y; + choice = 0; + } + break; + case SDL_KEYUP: + break; + case SDL_QUIT: + choice = 0; + buttons.up = SDLK_0; + break; + } + } + SDL_UpdateTexture(package.texture, NULL, package.screen->pixels, package.screen->pitch); + SDL_RenderCopy(package.renderer, package.texture, NULL, NULL); + SDL_RenderPresent(package.renderer); } - /*surface = SDL_LoadBMP("textures/ujc.bmp"); - if (surface == NULL) + return buttons; +} + +void initialize_map(Map_type *map) +{ + map->players = (Player_type*)malloc(sizeof(Player_type) * NUMBER_OF_CLIENTS); +} + +void free_map(Map_type* map) +{ + free(map->players); + free(map); +} + +int main(int argc, char** argv) +{ + Map_type* map = (Map_type*)malloc(sizeof(Map_type)); + initialize_map(map); + TTF_Init(); + SDL_package_type package; + SOCKET server = 0; + if (initialize_package(&package) != 0) { - SDL_DestroyRenderer(renderer); - SDL_DestroyWindow(win); - printf("Surface creation error\n"); + printf("NIE DZIALA"); SDL_Quit(); return 1; } - texture = SDL_CreateTextureFromSurface(renderer, surface); - SDL_FreeSurface(surface); - if (texture == NULL) + char* nick = (char*)malloc(STRING_LENGTH); + int important_treasure = -1; + int player_number = -1; + int quit = load_nickname(package, nick); + if(quit) { - SDL_DestroyRenderer(renderer); - SDL_DestroyWindow(win); - printf("Texture creation error\n"); + SDL_FreeSurface(package.screen); + SDL_DestroyTexture(package.texture); + SDL_DestroyRenderer(package.renderer); + SDL_DestroyWindow(package.win); SDL_Quit(); - return 1; - }*/ - int texW = 100; - int texH = 20; - SDL_Rect dstrect = { 0, 0, texW, texH }; - text_surface = TTF_RenderText_Solid(font, "This is my text.", foregroundColor); - texture = SDL_CreateTextureFromSurface(renderer, text_surface); - while(is_running) + return 0; + } + Buttons_type buttons_set = set_buttons(package); + if(buttons_set.up != SDLK_0) { - while (SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_KEYDOWN: - if (event.key.keysym.sym == SDLK_UP) { - send_key_to_server(LOCALHOST, "up"); - } - else if (event.key.keysym.sym == SDLK_DOWN) { - send_key_to_server(LOCALHOST, "down"); - } - else if (event.key.keysym.sym == SDLK_RIGHT) { - send_key_to_server(LOCALHOST, "right"); - } - else if (event.key.keysym.sym == SDLK_LEFT) { - send_key_to_server(LOCALHOST, "left"); - } - break; - case SDL_KEYUP: - break; - case SDL_QUIT: - is_running = 0; - break; - }; - }; - SDL_QueryTexture(texture, NULL, NULL, &texW, &texH); - SDL_RenderClear(renderer); - SDL_RenderCopy(renderer, texture, NULL, &dstrect); - SDL_RenderPresent(renderer); - SDL_Delay(1000); - } - SDL_FreeSurface(text_surface); - SDL_DestroyTexture(texture); - SDL_DestroyRenderer(renderer); - SDL_DestroyWindow(win); + server = connect_to_server(LOCALHOST, nick, map, &important_treasure); + if (server != 0) + { + if (initialize_players(buttons_set, server, map, package, important_treasure, &player_number) == 0) + { + start_game(buttons_set, server, map, package, player_number); + draw_end_game(&package, map); + } + close_connection_to_server(server); + } + } + SDL_FreeSurface(package.screen); + SDL_DestroyTexture(package.texture); + SDL_DestroyRenderer(package.renderer); + SDL_DestroyWindow(package.win); SDL_Quit(); return 0; diff --git a/client_thread_action.c b/client_thread_action.c new file mode 100644 index 0000000..df4a5bc --- /dev/null +++ b/client_thread_action.c @@ -0,0 +1,481 @@ +#include "client_thread_action.h" + +void move_player(Thread_args* arguments, const char* buf) +{ + int vertical; + int horizontal; + int delta_vertical=0; + int delta_horizontal=0; + int border_horizontal=0; + int border_vertical=0; + int vertical_border=0; + int horizontal_border=0; + int x=0; + int y=0; + int player_number = arguments->player_number; + int speed = SPEED; + if (arguments->map->players[player_number].frozen > 0) + { + return; + } + if (arguments->map->players[player_number].speed > 0) + { + speed = NEW_SPEED; + } + else + { + speed = SPEED; + } + if (strcmp(buf, "up") == 0) + { + printf("Player number %d sent UP\n", player_number); + if (WaitForSingleObject(arguments->map_mutex, INFINITE) == WAIT_OBJECT_0) + { + if (arguments->map->players[player_number].y % NEW_SPEED != 0) + { + speed = SPEED; + } + } + ReleaseMutex(arguments->map_mutex); + x = 0; + y = -speed; + //arguments->map->players[player_number].y -= speed; + delta_vertical = -speed; + delta_horizontal = 0; + border_horizontal = TEXTURE_SIZE - 1; + border_vertical = 0; + } + else if (strcmp(buf, "down") == 0) + { + printf("Player number %d sent DOWN\n", player_number); + if (WaitForSingleObject(arguments->map_mutex, INFINITE) == WAIT_OBJECT_0) + { + if (arguments->map->players[player_number].y % NEW_SPEED != 0) + { + speed = SPEED; + } + } + ReleaseMutex(arguments->map_mutex); + x = 0; + y = speed; + delta_vertical = speed + TEXTURE_SIZE - 1; + delta_horizontal = 0; + border_horizontal = TEXTURE_SIZE - 1; + border_vertical = 0; + } + else if (strcmp(buf, "right") == 0) + { + printf("Player number %d sent RIGHT\n", player_number); + if (WaitForSingleObject(arguments->map_mutex, INFINITE) == WAIT_OBJECT_0) + { + if (arguments->map->players[player_number].x % NEW_SPEED != 0) + { + speed = SPEED; + } + } + ReleaseMutex(arguments->map_mutex); + x = speed; + y = 0; + delta_vertical = 0; + delta_horizontal = speed + TEXTURE_SIZE - 1; + border_vertical = TEXTURE_SIZE - 1; + border_horizontal = 0; + } + else if (strcmp(buf, "left") == 0) + { + printf("Player number %d sent LEFT\n", player_number); + if (WaitForSingleObject(arguments->map_mutex, INFINITE) == WAIT_OBJECT_0) + { + if (arguments->map->players[player_number].x % NEW_SPEED != 0) + { + speed = SPEED; + } + } + ReleaseMutex(arguments->map_mutex); + x = -speed; + y = 0; + delta_vertical = 0; + delta_horizontal = -speed; + border_vertical = TEXTURE_SIZE - 1; + border_horizontal = 0; + } + vertical = (arguments->map->players[player_number].y + delta_vertical) / TEXTURE_SIZE; + horizontal = (arguments->map->players[player_number].x + delta_horizontal) / TEXTURE_SIZE; + vertical_border = ((arguments->map->players[player_number].y + delta_vertical + border_vertical) / TEXTURE_SIZE); + horizontal_border = ((arguments->map->players[player_number].x + delta_horizontal + border_horizontal) / TEXTURE_SIZE); + if (arguments->map->labyrinth[vertical][horizontal] != WALL && arguments->map->labyrinth[vertical_border][horizontal_border] != WALL) + { + if ((arguments->map->labyrinth[vertical][horizontal] >= TREASURE_OFFSET && arguments->map->labyrinth[vertical][horizontal] < TREASURE_OFFSET + NUMBER_OF_TREASURES) || (arguments->map->labyrinth[vertical_border][horizontal_border] >= TREASURE_OFFSET && arguments->map->labyrinth[vertical_border][horizontal_border] < TREASURE_OFFSET + NUMBER_OF_TREASURES)) + { + arguments->map->players[player_number].x += x; + arguments->map->players[player_number].y += y; + get_chest(arguments); + } + else if ((arguments->map->labyrinth[vertical][horizontal] >= SKILL_OFFSET && arguments->map->labyrinth[vertical][horizontal] < SKILL_OFFSET + NUMBER_OF_SKILLS) || (arguments->map->labyrinth[vertical_border][horizontal_border] >= SKILL_OFFSET && arguments->map->labyrinth[vertical_border][horizontal_border] < SKILL_OFFSET + NUMBER_OF_SKILLS)) + { + arguments->map->players[player_number].x += x; + arguments->map->players[player_number].y += y; + get_skill(arguments); + } + else + { + arguments->map->players[player_number].x += x; + arguments->map->players[player_number].y += y; + } + } +} + +void disconnect(Thread_args* arguments) +{ + int player_number = arguments->player_number; + printf("Player number %d has left\n", player_number); + if (WaitForSingleObject(arguments->map_mutex, INFINITE) == WAIT_OBJECT_0) + { + arguments->map->players[player_number].connected=0; + arguments->map->players[player_number].ready=0; + } + ReleaseMutex(arguments->map_mutex); +} + +void connect_to_client(Thread_args* arguments) +{ + char buf[STRING_LENGTH]; + int player_number = arguments->player_number; + SOCKET client_socket = arguments->map->players[player_number].socket; + strcpy(buf, "OK"); + send(client_socket, buf, STRING_LENGTH, 0); + recv(client_socket, buf, STRING_LENGTH, 0); + if (WaitForSingleObject(arguments->map_mutex, INFINITE) == WAIT_OBJECT_0) + { + int x, y; + arguments->map->players[player_number].points = 0; + do + { + x = rand() % arguments->map->size; + y = rand() % arguments->map->size; + } while (arguments->map->labyrinth[y][x] == WALL); + arguments->map->players[player_number].x = x * TEXTURE_SIZE; + arguments->map->players[player_number].y = y * TEXTURE_SIZE; + arguments->map->players[player_number].connected = 1; + arguments->map->players[player_number].ready = 0; + strcpy(arguments->map->players[player_number].nick, buf); + } + ReleaseMutex(arguments->map_mutex); + send_labyrinth_to_client(client_socket, arguments->map); + send_important_treasure_id_to_client(client_socket, arguments->map->players[player_number].important_treasure); +} + +void end_game(Thread_args* arguments) +{ + int player_number = arguments->player_number; + int rd = 1; + if (WaitForSingleObject(arguments->map_mutex, INFINITE) == WAIT_OBJECT_0) + { + arguments->map->players[player_number].has_left = 1; + } + ReleaseMutex(arguments->map_mutex); + if (WaitForSingleObject(arguments->ready_mutex, INFINITE) == WAIT_OBJECT_0) + { + rd = 1; + for (int i = 0; i < NUMBER_OF_CLIENTS; i++) + { + if (arguments->map->players[i].connected) + { + if (!arguments->map->players[i].has_left) + { + rd = 0; + } + } + } + *(arguments->everybody_left) = rd; + } + ReleaseMutex(arguments->ready_mutex); +} + +void get_skill(Thread_args* arguments) +{ + int player_number = arguments->player_number; + int left = arguments->map->players[player_number].x/TEXTURE_SIZE; + int top = arguments->map->players[player_number].y/TEXTURE_SIZE; + int right = (arguments->map->players[player_number].x+TEXTURE_SIZE-1)/TEXTURE_SIZE; + int bottom = (arguments->map->players[player_number].y+TEXTURE_SIZE-1)/TEXTURE_SIZE; + int skill_index; + for(int i=SKILL_OFFSET;imap_mutex, INFINITE) == WAIT_OBJECT_0) + { + if (left == right && top == bottom && arguments->map->labyrinth[top][left] == i) + { + skill_index = i - SKILL_OFFSET; + arguments->map->players[player_number].skill = skill_index; + arguments->map->labyrinth[top][left] = FLOOR; + arguments->map->skills_number--; + if (WaitForSingleObject(arguments->flags_mutex, INFINITE) == WAIT_OBJECT_0) + { + for (int i = 0; i < NUMBER_OF_CLIENTS; i++) + { + arguments->flags[i] = 2; + } + } + ReleaseMutex(arguments->flags_mutex); + } + } + ReleaseMutex(arguments->map_mutex); + } +} +void get_ping_initialize(Thread_args* arguments) +{ + char buf[STRING_LENGTH]; + int player_number = arguments->player_number; + SOCKET client_socket = arguments->map->players[player_number].socket; + int rd = 1; + strcpy(buf, "pong"); + send(client_socket, buf, STRING_LENGTH, 0); + if (WaitForSingleObject(arguments->ready_mutex, INFINITE) == WAIT_OBJECT_0) + { + rd = 1; + for (int i = 0; i < NUMBER_OF_CLIENTS; i++) + { + if (arguments->map->players[i].connected) + { + if (!arguments->map->players[i].ready) + { + rd = 0; + } + } + } + *(arguments->everybody_ready) = rd; + if (arguments->map->time == -1 && rd == 1) + { + arguments->map->time = 120; + ReleaseSemaphore(arguments->time_semaphore, 1, NULL); + } + } + ReleaseMutex(arguments->ready_mutex); + if (WaitForSingleObject(arguments->flags_mutex, INFINITE) == WAIT_OBJECT_0) + { + if(arguments->flags[player_number] == 2) + { + arguments->flags[player_number] = 0; + ReleaseMutex(arguments->flags_mutex); + strcpy(buf, "full_map"); + send(client_socket, buf, STRING_LENGTH, 0); + char* data = (char*)malloc(SIZE_OF_DATA); + if (WaitForSingleObject(arguments->map_mutex, INFINITE) == WAIT_OBJECT_0) + { + serialize_map_fully(data, arguments->map, arguments->everybody_ready, &player_number, 0); + } + ReleaseMutex(arguments->map_mutex); + send(client_socket, data, SIZE_OF_DATA, 0); + free(data); + } + else + { + ReleaseMutex(arguments->flags_mutex); + strcpy(buf, "important_map"); + send(client_socket, buf, STRING_LENGTH, 0); + char* data = (char*)malloc(SIZE_OF_IMPORTANT_DATA); + if (WaitForSingleObject(arguments->map_mutex, INFINITE) == WAIT_OBJECT_0) + { + serialize_map_important(data, arguments->map); + } + ReleaseMutex(arguments->map_mutex); + send(client_socket, data, SIZE_OF_IMPORTANT_DATA, 0); + free(data); + } + } +} + +void get_chest(Thread_args* arguments) +{ + int player_number = arguments->player_number; + int left = arguments->map->players[player_number].x/TEXTURE_SIZE; + int top = arguments->map->players[player_number].y/TEXTURE_SIZE; + int right = (arguments->map->players[player_number].x+TEXTURE_SIZE-1)/TEXTURE_SIZE; + int bottom = (arguments->map->players[player_number].y+TEXTURE_SIZE-1)/TEXTURE_SIZE; + int chest_index; + for(int i=TREASURE_OFFSET;imap_mutex, INFINITE) == WAIT_OBJECT_0) + { + if (left == right && top == bottom && arguments->map->labyrinth[top][left] == i) + { + chest_index = i - TREASURE_OFFSET; + arguments->map->players[player_number].treasures[chest_index] = 1; + arguments->map->labyrinth[top][left] = FLOOR; + if (chest_index == arguments->map->players[player_number].important_treasure) + { + arguments->map->players[player_number].points += 100; + } + else + { + arguments->map->players[player_number].points += 20; + } + if (WaitForSingleObject(arguments->flags_mutex, INFINITE) == WAIT_OBJECT_0) + { + for (int i = 0; i < NUMBER_OF_CLIENTS; i++) + { + arguments->flags[i] = 2; + } + } + ReleaseMutex(arguments->flags_mutex); + } + } + ReleaseMutex(arguments->map_mutex); + } +} + +int get_ping_game(Thread_args* arguments) +{ + char buf[STRING_LENGTH]; + int player_number = arguments->player_number; + SOCKET client_socket = arguments->map->players[player_number].socket; + if (WaitForSingleObject(arguments->map_mutex, INFINITE) == WAIT_OBJECT_0) + { + if (arguments->map->players[player_number].frozen > 0) + { + arguments->map->players[player_number].frozen--; + } + if (arguments->map->players[player_number].speed > 0) + { + arguments->map->players[player_number].speed--; + } + } + ReleaseMutex(arguments->map_mutex); + strcpy(buf, "pong"); + send(client_socket, buf, STRING_LENGTH, 0); + char* data; + if (WaitForSingleObject(arguments->map_mutex, INFINITE) == WAIT_OBJECT_0) + { + if (*(arguments->everybody_left) == 1 || arguments->map->time == 0) + { + strcpy(buf, "full_map"); + send(client_socket, buf, STRING_LENGTH, 0); + serialize_map_fully(data, arguments->map, arguments->everybody_ready, &player_number, 1); + ReleaseMutex(arguments->map_mutex); + send(client_socket, data, SIZE_OF_DATA, 0); + free(data); + return 1; + } + else + { + + if (WaitForSingleObject(arguments->flags_mutex, INFINITE) == WAIT_OBJECT_0) + { + if(arguments->flags[player_number] == 2) + { + arguments->flags[player_number] = 0; + ReleaseMutex(arguments->flags_mutex); + strcpy(buf, "full_map"); + send(client_socket, buf, STRING_LENGTH, 0); + data = (char*)malloc(SIZE_OF_DATA); + if (WaitForSingleObject(arguments->map_mutex, INFINITE) == WAIT_OBJECT_0) + { + serialize_map_fully(data, arguments->map, arguments->everybody_ready, &player_number, 0); + } + ReleaseMutex(arguments->map_mutex); + send(client_socket, data, SIZE_OF_DATA, 0); + free(data); + } + else + { + ReleaseMutex(arguments->flags_mutex); + strcpy(buf, "important_map"); + send(client_socket, buf, STRING_LENGTH, 0); + data = (char*)malloc(SIZE_OF_IMPORTANT_DATA); + if (WaitForSingleObject(arguments->map_mutex, INFINITE) == WAIT_OBJECT_0) + { + serialize_map_important(data, arguments->map); + } + ReleaseMutex(arguments->map_mutex); + send(client_socket, data, SIZE_OF_IMPORTANT_DATA, 0); + free(data); + } + } + } + } + return 0; +} + +void use_skill(Thread_args* args) +{ + int player_number = args->player_number; + Player_type* players = args->map->players; + switch(args->map->players[player_number].skill) + { + case 0: + if (WaitForSingleObject(args->map_mutex, INFINITE) == WAIT_OBJECT_0) + { + players[player_number].skill=-1; + int index = find_best_player_index_excluding_arg_player(args->map, player_number); + if (index >= 0) + { + for (int i = 0; i < NUMBER_OF_TREASURES; i++) + { + if (players[index].treasures[i] == 1) + { + players[player_number].treasures[i] = 1; + players[index].treasures[i] = 0; + if (i == players[player_number].important_treasure) + { + players[player_number].points += 100; + } + else + { + players[player_number].points += 20; + } + if (i == players[index].important_treasure) + { + players[index].points -= 100; + } + else + { + players[index].points -= 20; + } + break; + } + } + } + } + ReleaseMutex(args->map_mutex); + break; + case 1: + if (WaitForSingleObject(args->map_mutex, INFINITE) == WAIT_OBJECT_0) + { + players[player_number].skill=-1; + int index = find_best_player_index_excluding_arg_player(args->map, player_number); + if (index >= 0) + { + players[index].frozen = 250; + } + } + ReleaseMutex(args->map_mutex); + break; + case 2: + if (WaitForSingleObject(args->map_mutex, INFINITE) == WAIT_OBJECT_0) + { + players[player_number].skill=-1; + players[player_number].speed = 300; + } + ReleaseMutex(args->map_mutex); + break; + case 3: + if (WaitForSingleObject(args->map_mutex, INFINITE) == WAIT_OBJECT_0) + { + int x_temp, y_temp; + players[player_number].skill=-1; + int index = find_best_player_index_excluding_arg_player(args->map, player_number); + if (index >= 0) + { + x_temp = players[index].x; + y_temp = players[index].y; + players[index].x = players[player_number].x; + players[index].y = players[player_number].y; + players[player_number].x = x_temp; + players[player_number].y = y_temp; + } + } + ReleaseMutex(args->map_mutex); + break; + } +} \ No newline at end of file diff --git a/client_thread_action.h b/client_thread_action.h new file mode 100644 index 0000000..205aa08 --- /dev/null +++ b/client_thread_action.h @@ -0,0 +1,24 @@ +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include "../../../common/common_structures.h" + +void disconnect(Thread_args* arguments); + +void connect_to_client(Thread_args* arguments); + +void end_game(Thread_args* arguments); + +void get_skill(Thread_args* arguments); + +void get_ping_initialize(Thread_args* arguments); + +void get_chest(Thread_args* arguments); + +void move_player(Thread_args* arguments, const char* buf); + +int get_ping_game(Thread_args* arguments); + +void use_skill(Thread_args* args); \ No newline at end of file diff --git a/common_structures.h b/common_structures.h new file mode 100644 index 0000000..850aeaa --- /dev/null +++ b/common_structures.h @@ -0,0 +1,87 @@ +#pragma once +#define NUMBER_OF_CLIENTS 4 +#define PORT 7777 +#define SIZE_OF_DATA 2048 +#define SIZE_OF_IMPORTANT_DATA 128 +#define STRING_LENGTH 20 +#define SPEED 4 +#define NEW_SPEED 8 +#define TEXTURE_SIZE 16 +#define LOCALHOST "127.0.0.1" +#define NUMBER_OF_TREASURES 16 +#define TREASURE_OFFSET 16 +#define NUMBER_OF_SKILLS 4 +#define SKILL_OFFSET 50 +#define WALL 0 +#define FLOOR 1 +#define EXIT 2 +#include + +//struktura danych gracza +typedef struct Player_type +{ + //skĹ‚adowa pozioma pozycji gracza + int x; + //skĹ‚adowa pionowa pozycji gracza + int y; + //punkty gracza + int points; + //nick gracza + char nick[STRING_LENGTH]; + //gotowość gracza + int ready; + //gniazdo danego gracza do obsĹ‚ugi + SOCKET socket; + //czy gracz jest połączony + int connected; + // skarby zebrane przez gracza + int treasures[NUMBER_OF_TREASURES]; + // najwaĹĽniejszy skarb gracza + int important_treasure; + //posiadana umiejetnosc + int skill; + //zamroĹĽenie gracza + int frozen; + //przyspieszenie gracza + int speed; + // czy zakonczyl grÄ™ + int has_left; +}Player_type; + +//struktura mapy +typedef struct Map_type +{ + //rozmiar mapy + int size; + //tablica graczy + Player_type* players; + //dane labiryntu + unsigned char** labyrinth; + // obecna liczba umiÄ™tnoĹ›ci + int skills_number; + //mierzony czas + int time; +}Map_type; + +//struktura danych przesyĹ‚anych do klienta +typedef struct Thread_args +{ + //numer danego gracza + int player_number; + //wskaĹşnik na wspĂłlnÄ… mapÄ™ + Map_type* map; + //wskaznik na zmienna, czy gracze sa gotowi + int* everybody_ready; + //wskaznik na zmienna, czy gracze wyszli z labiryntu + int* everybody_left; + //uchwyt mutexa mapy + HANDLE map_mutex; + //uchwyt mutexa gotowoĹ›ci graczy + HANDLE ready_mutex; + //uchwyt semafora czasu + HANDLE time_semaphore; + //tablica flag do przesyĹ‚ania danych + int* flags; + //uchwyt mutexa flag + HANDLE flags_mutex; +}Thread_args; \ No newline at end of file diff --git a/connection.c b/connection.c new file mode 100644 index 0000000..18166d1 --- /dev/null +++ b/connection.c @@ -0,0 +1,211 @@ +#include"connection.h" + +void deserialize_map_fully(char* data, Map_type* map, int* everybody_ready, int* player_number, char* game_over) +{ + int position = 0; + for (int i = 0; i < NUMBER_OF_CLIENTS; i++) + { + memcpy(&(map->players[i].x), data + position, sizeof(int)); + position += sizeof(int); + memcpy(&(map->players[i].y), data + position, sizeof(int)); + position += sizeof(int); + memcpy(&(map->players[i].ready), data + position, sizeof(int)); + position += sizeof(int); + memcpy(&(map->players[i].connected), data + position, sizeof(int)); + position += sizeof(int); + memcpy(&(map->players[i].points), data + position, sizeof(int)); + position += sizeof(int); + int nick_length; + memcpy(&nick_length, data + position, sizeof(int)); + position += sizeof(int); + if (nick_length >= 0 && nick_length <= STRING_LENGTH) + { + memcpy(map->players[i].nick, data + position, nick_length); + map->players[i].nick[nick_length] = '\0'; + position += nick_length; + } + for (int j = 0; j < NUMBER_OF_TREASURES; j++) + { + memcpy(&(map->players[i].treasures[j]), data + position, sizeof(int)); + position += sizeof(int); + } + memcpy(&(map->players[i].skill), data + position, sizeof(int)); + position += sizeof(int); + memcpy(&(map->players[i].frozen), data + position, sizeof(int)); + position += sizeof(int); + memcpy(&(map->players[i].speed), data + position, sizeof(int)); + position += sizeof(int); + memcpy(&(map->players[i].has_left), data + position, sizeof(int)); + position += sizeof(int); + } + for (int j = 0; j < map->size; j++) + { + for (int k = 0; k < map->size; k++) + { + memcpy(&(map->labyrinth[j][k]), data + position, sizeof(unsigned char)); + position += sizeof(unsigned char); + } + } + memcpy(everybody_ready, data + position, sizeof(int)); + position += sizeof(int); + memcpy(&(map->time), data + position, sizeof(int)); + position += sizeof(int); + memcpy(player_number, data + position, sizeof(int)); + position += sizeof(int); + memcpy(game_over, data + position, sizeof(char)); + position += sizeof(char); +} + +void deserialize_map_important(char* data, Map_type* map, int* everybody_ready) +{ + int position = 0; + for (int i = 0; i < NUMBER_OF_CLIENTS; i++) + { + memcpy(&(map->players[i].x), data + position, sizeof(int)); + position += sizeof(int); + memcpy(&(map->players[i].y), data + position, sizeof(int)); + position += sizeof(int); + memcpy(&(map->players[i].connected), data + position, sizeof(int)); + position += sizeof(int); + memcpy(&(map->players[i].ready), data + position, sizeof(int)); + position += sizeof(int); + memcpy(&(map->players[i].skill), data + position, sizeof(int)); + position += sizeof(int); + memcpy(&(map->players[i].frozen), data + position, sizeof(int)); + position += sizeof(int); + memcpy(&(map->players[i].speed), data + position, sizeof(int)); + position += sizeof(int); + + } + memcpy(&(map->time), data + position, sizeof(int)); + position += sizeof(int); + memcpy(everybody_ready, data + position, sizeof(int)); + position += sizeof(int); +} + + +int ping_server(SOCKET s) +{ + int latency = 0; + char buf[STRING_LENGTH]; + clock_t start, end; + strcpy(buf, "ping"); + send(s, buf, STRING_LENGTH, 0); + start = clock(); + if (recv(s, buf, STRING_LENGTH, 0) > 0) + { + end = clock(); + latency = (end - start) / (CLOCKS_PER_SEC / 1000); + buf[5] = '\0'; + } + else + { + printf("Ping lost\n"); + } + return latency; +} + +void close_connection_to_server(SOCKET s) +{ + char buf[STRING_LENGTH]; + strcpy(buf, "disconnect"); + send(s, buf, STRING_LENGTH, 0); + closesocket(s); + WSACleanup(); +} + +void receive_full_data_from_server(SOCKET s, Map_type* map, int* everybody_ready, int* player_number, char* game_over) +{ + char* data = (char*)malloc(SIZE_OF_DATA); + recv(s, data, SIZE_OF_DATA, 0); + deserialize_map_fully(data, map, everybody_ready, player_number, game_over); + free(data); +} + +void receive_important_data_from_server(SOCKET s, Map_type* map, int* everybody_ready) +{ + char* data = (char*)malloc(SIZE_OF_IMPORTANT_DATA); + recv(s, data, SIZE_OF_IMPORTANT_DATA, 0); + deserialize_map_important(data, map, everybody_ready); + free(data); +} + +int ping_and_receive(SOCKET s, Map_type* map, int* everybody_ready, int* player_number, char* game_over) +{ + char buf[STRING_LENGTH]; + int latency = ping_server(s); + recv(s, buf, STRING_LENGTH, 0); + if (strcmp(buf, "full_map") == 0) + { + receive_full_data_from_server(s, map, everybody_ready, player_number, game_over); + } + else if (strcmp(buf, "important_map") == 0) + { + receive_important_data_from_server(s, map, everybody_ready); + } + return latency; +} + +void receive_important_treasure_id_from_server(SOCKET s, int* important_treasure) +{ + char* int_holder = (char*)malloc(sizeof(int)); + recv(s, int_holder, sizeof(int), 0); + memcpy(important_treasure, int_holder, sizeof(int)); + free(int_holder); +} + +SOCKET connect_to_server(const char* address, char* nick, Map_type* map, int* important_treasure) +{ + SOCKET s; + struct sockaddr_in sa; + WSADATA wsas; + WORD version; + int result; + version = MAKEWORD(2, 0); + WSAStartup(version, &wsas); + s = socket(AF_INET, SOCK_STREAM, 0); + memset((void*)(&sa), 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons(PORT); + sa.sin_addr.s_addr = inet_addr(address); + result = connect(s, (struct sockaddr FAR*) & sa, sizeof(sa)); + char buf[STRING_LENGTH]; + if (result == SOCKET_ERROR) + { + return 0; + } + else + { + strcpy(buf, "connect"); + send(s, buf, STRING_LENGTH, 0); + recv(s, buf, STRING_LENGTH, 0); + if (strcmp(buf, "OK") == 0) + { + strcpy(buf, nick); + send(s, buf, STRING_LENGTH, 0); + receive_labyrinth_from_server(s, map); + receive_important_treasure_id_from_server(s, important_treasure); + return s; + } + else + { + closesocket(s); + WSACleanup(); + return 0; + } + } +} + +void receive_labyrinth_from_server(SOCKET s, Map_type* map) +{ + char* int_holder = (char*)malloc(sizeof(int)); + recv(s, int_holder, sizeof(int), 0); + memcpy(&(map->size), int_holder, sizeof(int)); + map->labyrinth = (unsigned char**)malloc(map->size * sizeof(unsigned char*)); + for (int i = 0; i < map->size; i++) + { + map->labyrinth[i] = (unsigned char*)malloc(map->size * (sizeof(unsigned char))); + recv(s, map->labyrinth[i], map->size, 0); + } + free(int_holder); +} \ No newline at end of file diff --git a/connection.h b/connection.h new file mode 100644 index 0000000..ff7d00f --- /dev/null +++ b/connection.h @@ -0,0 +1,25 @@ +#define _CRT_SECURE_NO_WARNINGS +#include +#include +#include "../../../common/common_structures.h" +#include + +int ping_server(SOCKET s); + +void close_connection_to_server(SOCKET s); + +void receive_full_data_from_server(SOCKET s, Map_type* map, int* everybody_ready, int* player_number, char* game_over); + +void receive_important_data_from_server(SOCKET s, Map_type* map, int* everybody_ready); + +int ping_and_receive(SOCKET s, Map_type* map, int* everybody_ready, int* player_number, char* game_over); + +void receive_important_treasure_id_from_server(SOCKET s, int* important_treasure); + +SOCKET connect_to_server(const char* address, char* nick, Map_type* map, int* important_treasure); + +void receive_labyrinth_from_server(SOCKET s, Map_type* map); + +void deserialize_map_fully(char* data, Map_type* map, int* everybody_ready, int* player_number, char* game_over); + +void deserialize_map_important(char* data, Map_type* map, int* everybody_ready); \ No newline at end of file diff --git a/connection_to_client.c b/connection_to_client.c new file mode 100644 index 0000000..40dac08 --- /dev/null +++ b/connection_to_client.c @@ -0,0 +1,99 @@ +#include "connection_to_client.h" + +void send_labyrinth_to_client(SOCKET client, Map_type* map) +{ + char* int_holder = (char*)malloc(sizeof(int)); + memcpy(int_holder, &(map->size), sizeof(int)); + send(client, int_holder, sizeof(int), 0); + for (int i = 0; i < map->size; i++) + { + send(client, map->labyrinth[i], map->size, 0); + } + free(int_holder); +} + +void serialize_map_fully(char* data, Map_type* map, int* everybody_ready, int* player_number, char game_over) +{ + strcpy(data, ""); + int position = 0; + for (int i = 0; i < NUMBER_OF_CLIENTS; i++) + { + memcpy(data + position, &(map->players[i].x), sizeof(int)); + position += sizeof(int); + memcpy(data + position, &(map->players[i].y), sizeof(int)); + position += sizeof(int); + memcpy(data + position, &(map->players[i].ready), sizeof(int)); + position += sizeof(int); + memcpy(data + position, &(map->players[i].connected), sizeof(int)); + position += sizeof(int); + memcpy(data + position, &(map->players[i].points), sizeof(int)); + position += sizeof(int); + int length = strlen(map->players[i].nick); + memcpy(data + position, &length, sizeof(int)); + position += sizeof(int); + memcpy(data + position, map->players[i].nick, length); + position += length; + for (int j = 0; j < NUMBER_OF_TREASURES; j++) + { + memcpy(data + position, &(map->players[i].treasures[j]), sizeof(int)); + position += sizeof(int); + } + memcpy(data + position, &(map->players[i].skill), sizeof(int)); + position += sizeof(int); + memcpy(data + position, &(map->players[i].frozen), sizeof(int)); + position += sizeof(int); + memcpy(data + position, &(map->players[i].speed), sizeof(int)); + position += sizeof(int); + memcpy(data + position, &(map->players[i].has_left), sizeof(int)); + position += sizeof(int); + } + for (int j = 0; j < map->size; j++) + { + for (int k = 0; k < map->size; k++) + { + memcpy(data + position, &(map->labyrinth[j][k]), sizeof(unsigned char)); + position += sizeof(unsigned char); + } + } + memcpy(data + position, everybody_ready, sizeof(int)); + position += sizeof(int); + memcpy(data + position, &(map->time), sizeof(int)); + position += sizeof(int); + memcpy(data + position, player_number, sizeof(int)); + position += sizeof(int); + memcpy(data + position, &game_over, sizeof(char)); + position += sizeof(char); +} + +void serialize_map_important(char* data, Map_type* map) +{ + strcpy(data, ""); + int position = 0; + for (int i = 0; i < NUMBER_OF_CLIENTS; i++) + { + memcpy(data + position, &(map->players[i].x), sizeof(int)); + position += sizeof(int); + memcpy(data + position, &(map->players[i].y), sizeof(int)); + position += sizeof(int); + memcpy(data + position, &(map->players[i].connected), sizeof(int)); + position += sizeof(int); + memcpy(data + position, &(map->players[i].ready), sizeof(int)); + position += sizeof(int); + memcpy(data + position, &(map->players[i].skill), sizeof(int)); + position += sizeof(int); + memcpy(data + position, &(map->players[i].frozen), sizeof(int)); + position += sizeof(int); + memcpy(data + position, &(map->players[i].speed), sizeof(int)); + position += sizeof(int); + } + memcpy(data + position, &(map->time), sizeof(int)); + position += sizeof(int); +} + +void send_important_treasure_id_to_client(SOCKET s, int id) +{ + char* int_holder = (char*)malloc(sizeof(int)); + memcpy(int_holder, &id, sizeof(int)); + send(s, int_holder, sizeof(int), 0); + free(int_holder); +} \ No newline at end of file diff --git a/connection_to_client.h b/connection_to_client.h new file mode 100644 index 0000000..38ef384 --- /dev/null +++ b/connection_to_client.h @@ -0,0 +1,14 @@ +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include "../../../common/common_structures.h" + +void send_labyrinth_to_client(SOCKET client, Map_type* map); + +void serialize_map_important(char* data, Map_type* map); + +void serialize_map_fully(char* data, Map_type* map, int* everybody_ready, int* player_number, char game_over); + +void send_important_treasure_id_to_client(SOCKET s, int id); diff --git a/draw_functions.c b/draw_functions.c new file mode 100644 index 0000000..4d879e5 --- /dev/null +++ b/draw_functions.c @@ -0,0 +1,304 @@ +#include "draw_functions.h" + +void draw_text(const char* text, int position_x, int position_y, SDL_package_type package) +{ + SDL_Surface* text_surface; + SDL_Rect dstrect = { position_x, position_y, strlen(text)*5, FONT_SIZE }; + text_surface = TTF_RenderText_Solid(package.font, text, package.foregroundColor); + SDL_BlitSurface(text_surface, NULL, package.screen, &dstrect); + SDL_FreeSurface(text_surface); +} + +int initialize_package(SDL_package_type *package) +{ + package->foregroundColor = (SDL_Color){ 255, 255, 255 }; + package->backgroundColor = (SDL_Color){ 0, 0, 255 }; + package->player_colors[0] = (SDL_Color){ 255, 255, 0 }; + package->player_colors[1] = (SDL_Color){ 255, 0, 0 }; + package->player_colors[2] = (SDL_Color){ 0, 0, 255 }; + package->player_colors[3] = (SDL_Color){ 0, 255, 0 }; + package->font = TTF_OpenFont("open-sans/OpenSans-Bold.ttf", FONT_SIZE); + if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { + printf("SDL init error! Code: %s\n", SDL_GetError()); + return 1; + } + package->win = SDL_CreateWindow("420", 400, 200, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN ); + if (package->win == NULL) + { + printf("Window creation error\n"); + SDL_Quit(); + return 1; + } + package->renderer = SDL_CreateRenderer(package->win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + if (package->renderer == NULL) + { + SDL_DestroyWindow(package->win); + printf("Renderer creation error\n"); + SDL_Quit(); + return 1; + } + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); + SDL_RenderSetLogicalSize(package->renderer, SCREEN_WIDTH, SCREEN_HEIGHT); + SDL_SetRenderDrawColor(package->renderer, 0, 0, 0, 255); + SDL_SetWindowTitle(package->win, "Labirynt skarbow"); + package->screen = SDL_CreateRGBSurface(0, SCREEN_WIDTH, SCREEN_HEIGHT, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); + if (package->screen == NULL) + { + SDL_DestroyRenderer(package->renderer); + SDL_DestroyWindow(package->win); + printf("Surface creation error\n"); + SDL_Quit(); + return 1; + } + package->texture = SDL_CreateTexture(package->renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, SCREEN_WIDTH, SCREEN_HEIGHT); + if (package->texture == NULL) + { + SDL_DestroyRenderer(package->renderer); + SDL_DestroyWindow(package->win); + printf("Texture creation error\n"); + SDL_Quit(); + return 1; + } + package->color = SDL_MapRGB(package->screen->format, 0x00, 0x00, 0x00); + package->wall = SDL_LoadBMP("textures/wall.bmp"); + if (package->wall == NULL) + { + SDL_DestroyRenderer(package->renderer); + SDL_DestroyWindow(package->win); + printf("Wall creation error\n"); + SDL_Quit(); + return 1; + } + package->floor = SDL_LoadBMP("textures/free_space.bmp"); + if (package->floor == NULL) + { + SDL_DestroyRenderer(package->renderer); + SDL_DestroyWindow(package->win); + printf("Floor creation error\n"); + SDL_Quit(); + return 1; + } + package->chest = SDL_LoadBMP("textures/chest.bmp"); + if (package->chest == NULL) + { + SDL_DestroyRenderer(package->renderer); + SDL_DestroyWindow(package->win); + printf("Chest creation error\n"); + SDL_Quit(); + return 1; + } + package->skill = SDL_LoadBMP("textures/skill.bmp"); + if (package->skill == NULL) + { + SDL_DestroyRenderer(package->renderer); + SDL_DestroyWindow(package->win); + printf("Chest creation error\n"); + SDL_Quit(); + return 1; + } + package->frozen = SDL_LoadBMP("textures/frozen.bmp"); + if (package->frozen == NULL) + { + SDL_DestroyRenderer(package->renderer); + SDL_DestroyWindow(package->win); + printf("Frozen creation error\n"); + SDL_Quit(); + return 1; + } + package->icon = SDL_LoadBMP("textures/icon.bmp"); + if (package->icon == NULL) + { + SDL_DestroyRenderer(package->renderer); + SDL_DestroyWindow(package->win); + printf("Icon creation error\n"); + SDL_Quit(); + return 1; + } + package->exit = SDL_LoadBMP("textures/exit.bmp"); + if (package->exit == NULL) + { + SDL_DestroyRenderer(package->renderer); + SDL_DestroyWindow(package->win); + printf("Icon creation error\n"); + SDL_Quit(); + return 1; + } + + package->player_surfs[0] = SDL_LoadBMP("textures/player_yellow.bmp"); + package->player_surfs[1] = SDL_LoadBMP("textures/player_red.bmp"); + package->player_surfs[2] = SDL_LoadBMP("textures/player_blue.bmp"); + package->player_surfs[3] = SDL_LoadBMP("textures/player_green.bmp"); + + for (int i = 0; i < NUMBER_OF_CLIENTS; i++) + { + if (package->player_surfs[i] == NULL) + { + SDL_DestroyRenderer(package->renderer); + SDL_DestroyWindow(package->win); + printf("Player creation error\n"); + SDL_Quit(); + return 1; + } + } + + return 0; +} + +void draw_surface(SDL_package_type* package, SDL_Surface* surface, int x, int y) +{ + SDL_Rect dstrect = (SDL_Rect){ x, y, surface->w, surface->h }; + SDL_BlitSurface(surface, NULL, package->screen, &dstrect); +} + +void draw_labyrinth(SDL_package_type* package, Map_type* map) +{ + for (int i = 0; i < map->size; i++) + { + for (int j = 0; j < map->size; j++) + { + if (map->labyrinth[i][j] == WALL) + { + draw_surface(package, package->wall,TEXTURE_SIZE*j, TEXTURE_SIZE*i); + } + else if(map->labyrinth[i][j] == EXIT) + { + draw_surface(package, package->floor, TEXTURE_SIZE * j, TEXTURE_SIZE * i); + draw_surface(package, package->exit, TEXTURE_SIZE * j, TEXTURE_SIZE * i); + } + else + { + draw_surface(package, package->floor, TEXTURE_SIZE * j, TEXTURE_SIZE * i); + } + } + } +} +void draw_players(SDL_package_type* package, Map_type* map) +{ + for (int i = 0; i < NUMBER_OF_CLIENTS; i++) + { + if (map->players[i].connected == 1 && map->players[i].ready == 1 && map->players[i].has_left != 1) + { + draw_surface(package, package->player_surfs[i], map->players[i].x, map->players[i].y ); + if (map->players[i].frozen > 0) + { + draw_surface(package, package->frozen, map->players[i].x, map->players[i].y); + } + } + + } +} +void draw_chests(SDL_package_type* package, Map_type* map) +{ + for (int i = 0; i < map->size; i++) + { + for (int j = 0; j < map->size; j++) + { + if (map->labyrinth[i][j] >= TREASURE_OFFSET && map->labyrinth[i][j] < TREASURE_OFFSET + NUMBER_OF_TREASURES) + { + draw_surface(package, package->chest,TEXTURE_SIZE*j, TEXTURE_SIZE*i); + } + } + } +} + +void draw_skills(SDL_package_type* package, Map_type* map) +{ + for (int i = 0; i < map->size; i++) + { + for (int j = 0; j < map->size; j++) + { + if (map->labyrinth[i][j] >= SKILL_OFFSET && map->labyrinth[i][j] < SKILL_OFFSET + NUMBER_OF_SKILLS) + { + draw_surface(package, package->skill, TEXTURE_SIZE * j, TEXTURE_SIZE * i); + } + } + } + +} + +void draw_game_over(SDL_package_type* package, Map_type* map) +{ + int position_y = 50; + char buf[128]; + SDL_Color temp = package->foregroundColor; + SDL_FillRect(package->screen, NULL, package->color); + draw_text("Koniec gry", SCREEN_WIDTH/2 - 20, position_y, *package); + position_y += POSITION_Y; + for (int i = 0; i < NUMBER_OF_CLIENTS; i++) + { + if (map->players[i].connected) + { + package->foregroundColor = package->player_colors[i]; + sprintf(buf, "Nick: %s", map->players[i].nick); + draw_text(buf, SCREEN_WIDTH / 2 - 20, position_y, *package); + position_y += POSITION_Y; + sprintf(buf, "Punkty: %d", map->players[i].points); + draw_text(buf, SCREEN_WIDTH / 2 - 20, position_y, *package); + position_y += POSITION_Y; + if (!map->players[i].has_left) + { + draw_text("KARA ZA NIE BYCIE NA CZAS", SCREEN_WIDTH / 2 - 20, position_y, *package); + position_y += POSITION_Y; + } + } + } + package->foregroundColor = temp; +} + +void draw_info(SDL_package_type* package, Map_type* map) +{ + int position_y = 20; + char buf[128]; + char number_holder[10]; + sprintf(buf, "Czas: %d", map->time); + char tab[NUMBER_OF_SKILLS+1][20]; + strcpy(tab[0], ""); + strcpy(tab[1], "kradziez"); + strcpy(tab[2], "zamrozenie"); + strcpy(tab[3], "przyspieszenie"); + strcpy(tab[4], "teleportacja"); + draw_text(buf, map->size * TEXTURE_SIZE + 10, position_y, *package); + position_y += POSITION_Y; + for(int i=0;iplayers[i].connected) + { + SDL_Color temp = package->foregroundColor; + package->foregroundColor = package->player_colors[i]; + sprintf(buf, "Nick: %s", map->players[i].nick); + draw_text(buf, map->size * TEXTURE_SIZE + 10, position_y, *package); + position_y += POSITION_Y; + sprintf(buf, "Punkty: %d", map->players[i].points); + draw_text(buf, map->size * TEXTURE_SIZE + 10, position_y, *package); + position_y += POSITION_Y; + sprintf(buf, "Skarby: "); + for(int j=0;jplayers[i].treasures[j]==1) + { + sprintf(number_holder, "%d, ", j); + strcat(buf, number_holder); + } + } + if (strlen(buf) > strlen("Skarby: ")) + { + buf[strlen(buf) - 2] = '\0'; + } + draw_text(buf, map->size * TEXTURE_SIZE + 10, position_y, *package); + position_y += POSITION_Y; + sprintf(buf, "Umiejetnosc: %s", tab[map->players[i].skill+1]); + draw_text(buf, map->size * TEXTURE_SIZE + 10, position_y, *package); + position_y += POSITION_Y; + package->foregroundColor = temp; + } + } +} + +void draw_map(SDL_package_type* package, Map_type* map) +{ + draw_labyrinth(package, map); + draw_chests(package, map); + draw_skills(package, map); + draw_players(package, map); + draw_info(package, map); + } \ No newline at end of file diff --git a/draw_functions.h b/draw_functions.h new file mode 100644 index 0000000..eab6134 --- /dev/null +++ b/draw_functions.h @@ -0,0 +1,78 @@ +#define _CRT_SECURE_NO_WARNINGS +#include +#include +#include "../../../common/common_structures.h" + +#define FONT_SIZE 16 +#define POSITION_Y 35 +#define SCREEN_WIDTH 900 +#define SCREEN_HEIGHT 640 + +//struktura załadowanych zmiennych SDL +typedef struct SDL_package_type +{ + //okno + SDL_Window* win; + //renderer + SDL_Renderer* renderer; + //font tekstu + TTF_Font* font; + //powierzchnia ekranu + SDL_Surface* screen; + //tekstura do wyrysowywania + SDL_Texture * texture; + //kolor pierwszego planu + SDL_Color foregroundColor; + // kolor tła + SDL_Color backgroundColor; + //kolor typu int + int color; + //tekstura ściany + SDL_Surface* wall; + //tekstura podłogi (wolnej przestrzeni) + SDL_Surface* floor; + //tablica tekstur graczy + SDL_Surface* player_surfs[NUMBER_OF_CLIENTS]; + //tablica kolorow graczy + SDL_Color player_colors[NUMBER_OF_CLIENTS]; + //tekstura skrzyni + SDL_Surface* chest; + //teksura umiejetnosci + SDL_Surface* skill; + //teksura zamrażania + SDL_Surface* frozen; + //ikona początkowa + SDL_Surface* icon; + //wyjście z labiryntu + SDL_Surface* exit; +}SDL_package_type; + +//nadaje początkowe wartości paczce SDL +int initialize_package(SDL_package_type *package); + +//rysuje tekst na pozycji (x, y) +void draw_text(const char* text, int position_x, int position_y, SDL_package_type package); + +//dodaje wybraną powierzchnię do ekranu na pozycji (x, y) +void draw_surface(SDL_package_type* package, SDL_Surface* surface, int x, int y); + +//rysuje mapę (labirynt, gracze, skarby) +void draw_map(SDL_package_type* package, Map_type* map); + +//rysuje labirynt +void draw_labyrinth(SDL_package_type* package, Map_type* map); + +//rysuje graczy +void draw_players(SDL_package_type* package, Map_type* map); + +//rysuje skrzynie +void draw_chests(SDL_package_type* package, Map_type* map); + +//rysuje umiejetnosci +void draw_skills(SDL_package_type* package, Map_type* map); + +//rysuje punkty graczy +void draw_info(SDL_package_type* package, Map_type* map); + +//rysuje ekran koncowy +void draw_game_over(SDL_package_type* package, Map_type* map); \ No newline at end of file diff --git a/labyrinth.bmp b/labyrinth.bmp new file mode 100644 index 0000000..d5fc60e Binary files /dev/null and b/labyrinth.bmp differ diff --git a/open-sans/Apache License.txt b/open-sans/Apache License.txt new file mode 100644 index 0000000..989e2c5 --- /dev/null +++ b/open-sans/Apache License.txt @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/open-sans/OpenSans-Bold.ttf b/open-sans/OpenSans-Bold.ttf new file mode 100644 index 0000000..fd79d43 Binary files /dev/null and b/open-sans/OpenSans-Bold.ttf differ diff --git a/open-sans/OpenSans-BoldItalic.ttf b/open-sans/OpenSans-BoldItalic.ttf new file mode 100644 index 0000000..9bc8009 Binary files /dev/null and b/open-sans/OpenSans-BoldItalic.ttf differ diff --git a/open-sans/OpenSans-ExtraBold.ttf b/open-sans/OpenSans-ExtraBold.ttf new file mode 100644 index 0000000..21f6f84 Binary files /dev/null and b/open-sans/OpenSans-ExtraBold.ttf differ diff --git a/open-sans/OpenSans-ExtraBoldItalic.ttf b/open-sans/OpenSans-ExtraBoldItalic.ttf new file mode 100644 index 0000000..31cb688 Binary files /dev/null and b/open-sans/OpenSans-ExtraBoldItalic.ttf differ diff --git a/open-sans/OpenSans-Italic.ttf b/open-sans/OpenSans-Italic.ttf new file mode 100644 index 0000000..c90da48 Binary files /dev/null and b/open-sans/OpenSans-Italic.ttf differ diff --git a/open-sans/OpenSans-Light.ttf b/open-sans/OpenSans-Light.ttf new file mode 100644 index 0000000..0d38189 Binary files /dev/null and b/open-sans/OpenSans-Light.ttf differ diff --git a/open-sans/OpenSans-LightItalic.ttf b/open-sans/OpenSans-LightItalic.ttf new file mode 100644 index 0000000..68299c4 Binary files /dev/null and b/open-sans/OpenSans-LightItalic.ttf differ diff --git a/open-sans/OpenSans-Regular.ttf b/open-sans/OpenSans-Regular.ttf new file mode 100644 index 0000000..db43334 Binary files /dev/null and b/open-sans/OpenSans-Regular.ttf differ diff --git a/open-sans/OpenSans-Semibold.ttf b/open-sans/OpenSans-Semibold.ttf new file mode 100644 index 0000000..1a7679e Binary files /dev/null and b/open-sans/OpenSans-Semibold.ttf differ diff --git a/open-sans/OpenSans-SemiboldItalic.ttf b/open-sans/OpenSans-SemiboldItalic.ttf new file mode 100644 index 0000000..59b6d16 Binary files /dev/null and b/open-sans/OpenSans-SemiboldItalic.ttf differ diff --git a/players.c b/players.c new file mode 100644 index 0000000..52d261a --- /dev/null +++ b/players.c @@ -0,0 +1,24 @@ +#include"players.h" + +void send_key_to_server(SOCKET s, const char* key) +{ + char buf[STRING_LENGTH]; + strcpy(buf, key); + send(s, buf, STRING_LENGTH, 0); +} + +int check_if_on_exit(Map_type* map, int player_number) +{ + int left = map->players[player_number].x / TEXTURE_SIZE; + int top = map->players[player_number].y / TEXTURE_SIZE; + int right = (map->players[player_number].x + TEXTURE_SIZE - 1) / TEXTURE_SIZE; + int bottom = (map->players[player_number].y + TEXTURE_SIZE - 1) / TEXTURE_SIZE; + if (left == right && top == bottom && map->labyrinth[top][left] == EXIT) + { + return 1; + } + else + { + return 0; + } +} diff --git a/players.h b/players.h new file mode 100644 index 0000000..92f2170 --- /dev/null +++ b/players.h @@ -0,0 +1,23 @@ +#define _CRT_SECURE_NO_WARNINGS +#include +#include +#include "../../../common/common_structures.h" + +typedef struct Buttons_type +{ + //przycisk ruchu w górę + SDL_Keycode up; + //przycisk ruchu w dół + SDL_Keycode down; + //przycisk ruchu w prawo + SDL_Keycode right; + //przycisk ruchu w lewo + SDL_Keycode left; + //przycisk akcji + SDL_Keycode action; +}Buttons_type; + +void send_key_to_server(SOCKET s, const char* key); + +int check_if_on_exit(Map_type* map, int player_number); + diff --git a/server.c b/server.c index a44bfed..90782ef 100644 --- a/server.c +++ b/server.c @@ -3,12 +3,269 @@ #include #include #include - -#define PORT 420 +#include "../../../common/common_structures.h" +#include"connection_to_client.h" +#include"additives.h" +#include"client_thread_action.h" #pragma comment(lib, "Ws2_32.lib") -int main() { +DWORD WINAPI time_thread(void* args) +{ + Thread_args* arguments = (Thread_args*)args; + if (WaitForSingleObject(arguments->time_semaphore, INFINITE) == WAIT_OBJECT_0) + { + do + { + Sleep(1000); + arguments->map->time--; + } while (arguments->map->time > 0); + } + ReleaseSemaphore(arguments->time_semaphore, 1, NULL); + free(arguments); + return 0; +} + +DWORD WINAPI skills_thread(void* args) +{ + Thread_args* arguments = (Thread_args*)args; + int max_skills_number = 7; + printf("Uruchomiono watek umiejetnosci\n"); + while (!(*(arguments->everybody_ready))) + { + Sleep(1000); + } + printf("Watek umiejetnosci zaczyna\n"); + while (arguments->map->time != 0 && *(arguments->everybody_left) == 0) + { + Sleep(4000); + int x, y, skill_id; + do + { + x = rand() % arguments->map->size; + y = rand() % arguments->map->size; + } while (arguments->map->labyrinth[y][x] != FLOOR ); + skill_id = rand() % NUMBER_OF_SKILLS; + if(WaitForSingleObject(arguments->map_mutex, INFINITE) == WAIT_OBJECT_0) + { + printf("Dodano umiejetnosc\n"); + if (arguments->map->skills_number<= max_skills_number) + { + arguments->map->labyrinth[y][x] = SKILL_OFFSET + skill_id; + arguments->map->skills_number++; + printf("Dodano umiejetnosc\n"); + if(WaitForSingleObject(arguments->flags_mutex, INFINITE)==WAIT_OBJECT_0) + { + for(int i=0;iflags[i] = 2; + } + } + ReleaseMutex(arguments->flags_mutex); + } + } + ReleaseMutex(arguments->map_mutex); + } + free(arguments); + return 0; +} + +DWORD WINAPI client_thread(void* args) +{ + char buf[STRING_LENGTH]; + int lost_client = 0; + Thread_args* arguments = (Thread_args*)args; + int player_number = arguments->player_number; + SOCKET client_socket = arguments->map->players[player_number].socket; + int byte_no = SIZE_OF_DATA; + srand((unsigned int)time(NULL) * GetCurrentThreadId()); + if(*(arguments->everybody_ready)) + { + recv(client_socket, buf, STRING_LENGTH, 0); + if(strcmp(buf, "connect")==0) + { + strcpy(buf, "game_started"); + send(client_socket, buf, STRING_LENGTH, 0); + lost_client = 1; + } + } + while (!(*(arguments->everybody_ready))) + { + if (recv(client_socket, buf, STRING_LENGTH, 0) > 0) + { + //gracz dołącza do gry + if (strcmp(buf, "connect")==0) + { + connect_to_client(arguments); + if (WaitForSingleObject(arguments->flags_mutex) == WAIT_OBJECT_0) + { + for (int i = 0; i < NUMBER_OF_CLIENTS; i++) + { + arguments->flags[i] = 2; + } + } + ReleaseMutex(arguments->flags_mutex); + } + //gracz zgłasza gotowość + else if (strcmp(buf, "ready")==0) + { + if (WaitForSingleObject(arguments->map_mutex, INFINITE) == WAIT_OBJECT_0) + { + arguments->map->players[player_number].ready = 1; + } + ReleaseMutex(arguments->map_mutex); + } + //gracz zgłasza brak gotowości + else if (strcmp(buf, "not_ready")==0) + { + if (WaitForSingleObject(arguments->map_mutex, INFINITE) == WAIT_OBJECT_0) + { + arguments->map->players[player_number].ready = 0; + } + ReleaseMutex(arguments->map_mutex); + } + //gracz odłącza się od rozrywki + else if (strcmp(buf, "disconnect")==0) + { + disconnect(arguments); + if (WaitForSingleObject(arguments->flags_mutex, INFINITE) == WAIT_OBJECT_0) + { + for (int i = 0; i < NUMBER_OF_CLIENTS; i++) + { + arguments->flags[i] = 2; + } + } + ReleaseMutex(arguments->flags_mutex); + //zakończenie wątku + free(arguments); + return 0; + } + else if (strcmp(buf, "ping")==0) + { + get_ping_initialize(arguments); + } + } + + } + int speed = SPEED; + while (!lost_client) + { + if (recv(client_socket, buf, STRING_LENGTH, 0) > 0) + { + if(strcmp(buf, "up")==0 || strcmp(buf, "down")==0 || strcmp(buf, "right")==0 || strcmp(buf, "left")==0) + { + move_player(arguments, buf); + } + else if (strcmp(buf, "ping") == 0) + { + if (get_ping_game(arguments) == 1) + { + break; + } + } + /*else if (strcmp(buf, "chest")==0) + { + get_chest(arguments); + } + else if (strcmp(buf, "get_skill")==0) + { + get_skill(arguments); + }*/ + else if (strcmp(buf, "end_game") == 0) + { + end_game(arguments); + if (WaitForSingleObject(arguments->flags_mutex, INFINITE) == WAIT_OBJECT_0) + { + for (int i = 0; i < NUMBER_OF_CLIENTS; i++) + { + arguments->flags[i] = 2; + } + } + ReleaseMutex(arguments->flags_mutex); + } + else if(strcmp(buf, "skill")==0) + { + use_skill(arguments); + } + else if (strcmp(buf, "disconnect")==0) + { + disconnect(arguments); + if (WaitForSingleObject(arguments->flags_mutex, INFINITE) == WAIT_OBJECT_0) + { + for (int i = 0; i < NUMBER_OF_CLIENTS; i++) + { + arguments->flags[i] = 2; + } + } + ReleaseMutex(arguments->flags_mutex); + } + else + { + printf("NIEZROZUMIALE\n"); + } + } + else + { + printf("Lost connection to client\n"); + lost_client = 1; + //arguments->map->players[player_number].connected = 0; + } + } + + free(arguments); + return 0; +} + +int main() +{ + srand((unsigned int)time(NULL)); + HANDLE map_mutex, ready_mutex, time_semaphore, flags_mutex; + map_mutex = CreateMutex(NULL, FALSE, NULL); + ready_mutex = CreateMutex(NULL, FALSE, NULL); + time_semaphore = CreateSemaphore(NULL, 0, 1, NULL); + flags_mutex = CreateMutex(NULL, FALSE, NULL); + Map_type map; + int flags[NUMBER_OF_CLIENTS]; + read_BMP("labyrinth.bmp", &map); + set_exit(&map); + set_treasures(&map); + map.skills_number = 0; + map.time = -1; + int everybody_ready = 0; + int everybody_left = 0; + Thread_args *thread_args; + Player_type players[NUMBER_OF_CLIENTS]; + for (int i = 0; i < NUMBER_OF_CLIENTS; i++) + { + flags[i] = 0; + players[i].connected = 0; + strcpy(players[i].nick, " "); + players[i].ready = 0; + players[i].x = 0; + players[i].y = 0; + players[i].points = 0; + players[i].skill = -1; + players[i].has_left = 0; + int continue_drawing = 0; + do + { + continue_drawing = 0; + players[i].important_treasure = rand() % NUMBER_OF_TREASURES; + for(int j=0; j < i; j++) + { + if (players[i].important_treasure == players[j].important_treasure) + { + continue_drawing = 1; + } + } + } while (continue_drawing); + for (int j = 0; j < NUMBER_OF_TREASURES; j++) + { + players[i].treasures[j] = 0; + } + + } + map.players = players; WSADATA wsas; int result; WORD wersja; @@ -29,58 +286,63 @@ int main() { printf("Cannot bind socket"); exit(0); } - result = listen(s, 4); + result = listen(s, NUMBER_OF_CLIENTS); SOCKET si; struct sockaddr_in sc; int lenc; - char buf[20] = "PONG"; + char buf[STRING_LENGTH] = "PONG"; + DWORD id; + thread_args = (Thread_args*)malloc(sizeof(Thread_args)); + thread_args->everybody_ready = &everybody_ready; + thread_args->everybody_left = &everybody_left; + thread_args->map_mutex = map_mutex; + thread_args->ready_mutex = ready_mutex; + thread_args->time_semaphore = time_semaphore; + thread_args->map = ↦ + thread_args->flags_mutex = flags_mutex; + thread_args->flags = flags; + CreateThread(NULL, 0, skills_thread, (void*)thread_args, 0, &id); + thread_args = (Thread_args*)malloc(sizeof(Thread_args)); + thread_args->everybody_ready = &everybody_ready; + thread_args->everybody_left = &everybody_left; + thread_args->map_mutex = map_mutex; + thread_args->ready_mutex = ready_mutex; + thread_args->time_semaphore = time_semaphore; + thread_args->map = ↦ + thread_args->flags_mutex = flags_mutex; + thread_args->flags = flags; + CreateThread(NULL, 0, time_thread, (void*)thread_args, 0, &id); while (1) { lenc = sizeof(sc); si = accept(s, (struct sockaddr FAR*) &sc, &lenc); printf("Client accepted\n"); - //trzeba dac do nowego watku i odpowienio konczyc petle - /*while (1) + + thread_args = (Thread_args*)malloc(sizeof(Thread_args)); + thread_args->everybody_ready = &everybody_ready; + thread_args->everybody_left = &everybody_left; + thread_args->map_mutex = map_mutex; + thread_args->ready_mutex = ready_mutex; + thread_args->time_semaphore = time_semaphore; + thread_args->flags_mutex = flags_mutex; + thread_args->flags = flags; + for(int i=0;i 0) { - buf[5] = '\0'; - printf("Received %s from client, sending PONG\n", buf); - } - else { - printf("ERROR\n"); - } - strcpy(buf, "PONG"); - send(si, buf, 30, 0); - }*/ - if (recv(si, buf, 20, 0) > 0) - { - if (strcmp(buf, "up") == 0) + if(!players[i].connected) { - printf("GURA\n"); + players[i].socket=si; + thread_args->player_number = i; + break; } - else if (strcmp(buf, "down") == 0) - { - printf("DUU\n"); - } - else if (strcmp(buf, "right") == 0) - { - printf("PRAWO\n"); - } - else if (strcmp(buf, "left") == 0) - { - printf("LEWO\n"); - } - else - { - printf("NIEZROZUMIALE\n"); - } - } - else - { - printf("ERROR\n"); } + thread_args->map = ↦ + CreateThread(NULL, 0, client_thread, (void*)thread_args,0, &id); } + CloseHandle(time_semaphore); + CloseHandle(map_mutex); + CloseHandle(ready_mutex); + free(map.labyrinth); closesocket(si); WSACleanup(); return 0; diff --git a/textures/chest.bmp b/textures/chest.bmp new file mode 100644 index 0000000..b502147 Binary files /dev/null and b/textures/chest.bmp differ diff --git a/textures/cos.bmp b/textures/cos.bmp new file mode 100644 index 0000000..252892b Binary files /dev/null and b/textures/cos.bmp differ diff --git a/textures/exit.bmp b/textures/exit.bmp new file mode 100644 index 0000000..050caa3 Binary files /dev/null and b/textures/exit.bmp differ diff --git a/textures/exit2.bmp b/textures/exit2.bmp new file mode 100644 index 0000000..eb1aa36 Binary files /dev/null and b/textures/exit2.bmp differ diff --git a/textures/free_space.bmp b/textures/free_space.bmp new file mode 100644 index 0000000..58a02f2 Binary files /dev/null and b/textures/free_space.bmp differ diff --git a/textures/free_space2.bmp b/textures/free_space2.bmp new file mode 100644 index 0000000..06d8367 Binary files /dev/null and b/textures/free_space2.bmp differ diff --git a/textures/frozen.bmp b/textures/frozen.bmp new file mode 100644 index 0000000..5ee6a47 Binary files /dev/null and b/textures/frozen.bmp differ diff --git a/textures/icon.bmp b/textures/icon.bmp new file mode 100644 index 0000000..81ea075 Binary files /dev/null and b/textures/icon.bmp differ diff --git a/textures/player_blue.bmp b/textures/player_blue.bmp new file mode 100644 index 0000000..9f7122d Binary files /dev/null and b/textures/player_blue.bmp differ diff --git a/textures/player_green.bmp b/textures/player_green.bmp new file mode 100644 index 0000000..3887e82 Binary files /dev/null and b/textures/player_green.bmp differ diff --git a/textures/player_red.bmp b/textures/player_red.bmp new file mode 100644 index 0000000..ce9ef6e Binary files /dev/null and b/textures/player_red.bmp differ diff --git a/textures/player_yellow.bmp b/textures/player_yellow.bmp new file mode 100644 index 0000000..634711f Binary files /dev/null and b/textures/player_yellow.bmp differ diff --git a/textures/skill.bmp b/textures/skill.bmp new file mode 100644 index 0000000..23db179 Binary files /dev/null and b/textures/skill.bmp differ diff --git a/textures/wall.bmp b/textures/wall.bmp new file mode 100644 index 0000000..19326a5 Binary files /dev/null and b/textures/wall.bmp differ diff --git a/textures/wall2.bmp b/textures/wall2.bmp new file mode 100644 index 0000000..8fa80e7 Binary files /dev/null and b/textures/wall2.bmp differ