/* * File: game.c * Author: Arthur Brandao * * Created on 28 novembre 2018 */ #define _XOPEN_SOURCE 500 #include #include #include "error.h" #include "str.h" #include "file.h" #include "game.h" #include "bomberstudent_server.h" /* --- Extern --- */ Game game[MAXGAME]; int nbGame = 0; pthread_mutex_t gameMutex[MAXGAME]; pthread_mutex_t playerMutex[MAXGAME * MAXPLAYER]; /* --- Fonctions privées --- */ /** * Transforme le fichier map en un tableau 2D * @param char* Le contenu du fichier map * @param int Largeur de la map * @param int Hauteur de la map * @return char** La map parser */ char** parse_map(char* mapContent, int width, int height) { char** map = malloc(sizeof (char*) * width); //Creation des colonnes for (int i = 0; i < width; i++) { map[i] = malloc(sizeof (char) * height); } //Remplissage for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { map[j][i] = *mapContent; mapContent++; } mapContent++; } return map; } /** * Transforme un tableau 2D en une chaine * @param char** Le contenu du fichier map * @param int Largeur de la map * @param int Hauteur de la map * @return char* La map */ char* unparse_map(char** map, int width, int height) { int pos = 0; char* mapContent = malloc(sizeof (char) * (width * height + 1)); memset(mapContent, 0, width * height + 1); //Remplissage for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { mapContent[pos++] = map[j][i]; } } return mapContent; } /** * Cherche le joueur à qui appartient un objet * @param Game* La game du joueur * @param int Le type de l'objet * @param int X de l'objet * @param int Y de l'objet * @return Player* Le joueur trouvé ou NULL */ Player* search_player_object(Game* g, int type, int x, int y) { obj_node* objn; for (int i = 0; i < MAXPLAYER; i++) { if (g->player[i]->ini) { objn = object_search(g->player[i]->bomb, type, x, y); if (objn != NULL) { return g->player[i]; } } } return NULL; } /* --- Fonctions publiques --- */ boolean ini_games() { //Ini les games for (int i = 0; i < MAXGAME; i++) { game[i].active = false; game[i].index = i; } //Ini les mutex des games for (int i = 0; i < MAXGAME; i++) { if (pthread_mutex_init(&gameMutex[i], NULL) != 0) { adderror("Impossible d'initialiser les mutex des games"); return false; } } //Ini les mutex des joueurs des games for (int i = 0; i < MAXGAME * MAXPLAYER; i++) { if (pthread_mutex_init(&playerMutex[i], NULL) != 0) { adderror("Impossible d'initialiser les mutex des joueurs"); return false; } } return true; } void list_map(JsonArray* res) { char** result; int nbResult; //Regarde les fichiers dans le dossier result = file_list(MAPDIR, &nbResult); for (int i = 0; i < nbResult; i++) { add_array_string(res, result[i]); free(result[i]); } free(result); } int list_game(JsonArray* res) { JsonEncoder gameJson; int compteur = 0, i = 0; //Si il n' y a aucune game if (nbGame == 0) { return 0; } //Initialisation json ini_encoder(&gameJson); //Ajoute chaque game while (compteur < nbGame && i < MAXGAME) { pthread_mutex_lock(&gameMutex[i]); if (!game[i].active) { pthread_mutex_unlock(&gameMutex[i]); i++; continue; } //Creation objet json add_string(&gameJson, "name", game[i].name); add_integer(&gameJson, "nbPlayer", game[i].nbPlayer); add_string(&gameJson, "map", game[i].mapName); //Ajout dans le tableau add_array_object(res, &gameJson); //Nettoyage encoder objet clean_json_encoder(&gameJson); //Incremente pthread_mutex_unlock(&gameMutex[i]); i++; compteur++; } return nbGame; } int* map_size(char* map) { int* res; res = malloc(sizeof (int) * 2); res[WIDTH] = 0; res[HEIGHT] = 1; //Parcours la 1er ligne pour compter le nombre de caractère while (*map != '\n' && *map != '\0') { res[WIDTH]++; map++; } if (*map == '\0') { return res; } //Compte les lignes map++; while (*map != '\0') { if (*map == '\n') { res[HEIGHT]++; } map++; } return res; } int create_game(char* name, char* map) { int length, index = 0; char* path; int* size; //Regarde si il reste une game de disponnible if (nbGame == MAXGAME) { return ERR; } //Cherche une game libre while (index < MAXGAME) { pthread_mutex_lock(&gameMutex[index]); if (game[index].active == false) { break; } pthread_mutex_unlock(&gameMutex[index]); index++; } //Recup la map length = strlen(MAPDIR) + strlen(map); path = new_string(length); snprintf(path, length + 1, "%s%s", MAPDIR, map); game[index].mapContent = file_get_content(path); //Calcul taille de la map size = map_size(game[index].mapContent); //Set Up game[index].active = true; game[index].name = string_copy(name); game[index].nbPlayer = 0; game[index].mapName = string_copy(map); game[index].width = size[WIDTH]; game[index].height = size[HEIGHT]; game[index].map = parse_map(game[index].mapContent, size[WIDTH], size[HEIGHT]); for (int i = 0; i < MAXPLAYER; i++) { game[index].player[i] = malloc(sizeof (Player)); game[index].player[i]->ini = false; } game[index].object = malloc(sizeof (Object)); object_ini(game[index].object); //object_add(game[index].object, OBJ_MAJOR, 1, 1); pthread_mutex_unlock(&gameMutex[index]); //Retourne la position de la partie dans le tableau nbGame++; free(path); free(size); return index; } int add_player(Game* g, int cliId) { int index = 0; Client* cli; //Verif que la game n'est pas deja pleine pthread_mutex_lock(&gameMutex[g->index]); if (g->nbPlayer >= MAXPLAYER) { pthread_mutex_unlock(&gameMutex[g->index]); return ERR; } //Cherche un joueur non initialisé while (index < MAXPLAYER) { pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]); if (!g->player[index]->ini) { break; } pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]); index++; } //Recup du client cli = get_client(cliId); if (cli == NULL) { pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]); pthread_mutex_unlock(&gameMutex[g->index]); return ERR; } //Creation du joueur create_player(g->player[index], cli); g->nbPlayer++; pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]); pthread_mutex_unlock(&gameMutex[g->index]); return index; } void describe_game(Game* g, int playerIndex, JsonEncoder* desc) { JsonEncoder player; JsonEncoder map; JsonArray players; char* content; //Initialisation ini_encoder(&player); ini_encoder(&map); ini_array_encoder(&players); //Info map pthread_mutex_lock(&gameMutex[g->index]); content = remove_char(g->mapContent, '\n'); //La map sans \n car interdit en JSON add_integer(&map, "width", g->width); add_integer(&map, "height", g->height); add_string(&map, "content", content); free(content); //Ajout info add_integer(desc, "nbPlayers", g->nbPlayer); add_object(desc, "map", &map); //Ajout info courte joueur //printf("Add players\n"); for (int i = 0; i < MAXPLAYER; i++) { pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + i]); if (g->player[i]->ini) { describe_short_player(g->player[i], &player); add_array_object(&players, &player); clean_json_encoder(&player); } pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]); } //printf("Fin Add players\n"); add_array(desc, "players", &players); //Si besoins ajout un joueur if (playerIndex >= 0 && playerIndex < MAXPLAYER) { pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]); if (g->player[playerIndex]->ini) { describe_player(g->player[playerIndex], &player); add_object(desc, "player", &player); clean_json_encoder(&player); } pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]); } //Nettoyage pthread_mutex_unlock(&gameMutex[g->index]); clean_json_encoder(&map); clean_json_array(&players); } boolean notify_player(Game* g, char* method, char* ressource, JsonEncoder* param, int excludePlayerId) { boolean res = true; pthread_mutex_lock(&gameMutex[g->index]); //Regarde si la game est active if (!g->active) { pthread_mutex_unlock(&gameMutex[g->index]); return false; } //Parcours les joeurs de la game for (int i = 0; i < MAXPLAYER; i++) { //Si joueur actif pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + i]); if (g->player[i]->ini && g->player[i]->id != excludePlayerId) { res = res && notify_client(g->player[i]->cli, method, ressource, param); } pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]); } pthread_mutex_unlock(&gameMutex[g->index]); return res; } boolean player_collision(Game* g, int x, int y) { for (int i = 0; i < MAXPLAYER; i++) { if (g->player[i]->ini) { if (g->player[i]->x == x && g->player[i]->y == y) { return true; } } } return false; } boolean player_collision_index(Game* g, int x, int y, int* index) { for (int i = 0; i < MAXPLAYER; i++) { if (g->player[i]->ini) { if (g->player[i]->x == x && g->player[i]->y == y) { *index = i; return true; } } } return false; } boolean bomb_explode(Game* g, int playerIndex, int x, int y, JsonEncoder* json) { JsonEncoder object, notif, coord; JsonArray bomb, bonus, chain, explosion; int res, index, cBomb = 0, cBonus = 0, cChain = 0; obj_node* objn; //Inie json ini_encoder(&object); ini_encoder(¬if); ini_encoder(&coord); ini_array_encoder(&bomb); ini_array_encoder(&bonus); ini_array_encoder(&chain); ini_array_encoder(&explosion); //Mutex pthread_mutex_lock(&gameMutex[g->index]); if (playerIndex >= 0) pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]); //Determine le type de la bombe switch (g->map[x][y]) { case '1': add_string(json, "type", "classic"); g->player[playerIndex]->classicBomb++; g->player[playerIndex]->nbBomb--; objn = object_search(g->player[playerIndex]->bomb, OBJ_BCLASSIC, x, y); object_delete(g->player[playerIndex]->bomb, objn); break; case '2': add_string(json, "type", "mine"); g->player[playerIndex]->mine++; g->player[playerIndex]->nbBomb--; objn = object_search(g->player[playerIndex]->bomb, OBJ_BMINE, x, y); object_delete(g->player[playerIndex]->bomb, objn); break; case '3': add_string(json, "type", "remote"); g->player[playerIndex]->remoteBomb++; g->player[playerIndex]->nbBomb--; objn = object_search(g->player[playerIndex]->bomb, OBJ_BREMOTE, x, y); object_delete(g->player[playerIndex]->bomb, objn); break; default: if (playerIndex >= 0) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]); pthread_mutex_unlock(&gameMutex[g->index]); return false; } //Determine la position de la bombe char pos[20]; memset(pos, 0, 20); snprintf(pos, 20, "%d,%d", x, y); add_string(json, "pos", pos); //Ajoute coord explosion add_integer(&coord, "x", x); add_integer(&coord, "y", y); add_array_object(&explosion, &coord); clean_json_encoder(&coord); //Calcul l'explosion non mine if (g->map[x][y] != '2') { g->map[x][y] = '_'; //Si le joueur à un bonus if (g->player[playerIndex]->firePower > 0) { add_boolean(json, "bonus", true); } else { add_boolean(json, "bonus", false); } //Vers le haut for (int i = 0; i < 2 + g->player[playerIndex]->firePower; i++) { //Si on est dans la map if (y - 1 - i >= 0) { //Si un mur destructible if (g->map[x][y - 1 - i] == '*') { g->map[x][y - 1 - i] = '_'; res = spawn_object(g, x, y - 1 - i, &object); if (res == 1) { //Bombe cBomb++; add_array_object(&bomb, &object); clean_json_encoder(&object); } else if (res == 2) { //Bonus Malus cBonus++; add_array_object(&bonus, &object); clean_json_encoder(&object); } //Ajoute coord explosion add_integer(&coord, "x", x); add_integer(&coord, "y", y - 1 - i); add_array_object(&explosion, &coord); clean_json_encoder(&coord); break; } //Si un joueur if (player_collision_index(g, x, y - 1 - i, &index)) { if (index != playerIndex) pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]); if (g->player[index]->major == 0) { //Baisse la vie g->player[index]->life = g->player[index]->life - (g->player[index]->maxLife * (DAMAGEBOMB - (0.1 * i))); //Notification du joueur describe_player(g->player[index], ¬if); if (!notify_client(g->player[index]->cli, "POST", "attack/affect", ¬if)) { adderror("Impossible de notifer le client"); } clean_json_encoder(¬if); } if (index != playerIndex) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]); } //Si une bombe if (g->map[x][y - 1 - i] == '1' || g->map[x][y - 1 - i] == '2' || g->map[x][y - 1 - i] == '3') { cChain++; bomb_chain(g, playerIndex, x, y - 1 - i, &chain, &explosion); } //Si un mur solide if (g->map[x][y - 1 - i] == '-') { break; } //Ajoute coord explosion add_integer(&coord, "x", x); add_integer(&coord, "y", y - 1 - i); add_array_object(&explosion, &coord); clean_json_encoder(&coord); } else { break; } } //Vers le bas for (int i = 0; i < 2 + g->player[playerIndex]->firePower; i++) { //Si on est dans la map if (y + 1 + i <= g->height) { //Si un mur destructible if (g->map[x][y + 1 + i] == '*') { g->map[x][y + 1 + i] = '_'; res = spawn_object(g, x, y + 1 + i, &object); if (res == 1) { //Bombe cBomb++; add_array_object(&bomb, &object); clean_json_encoder(&object); } else if (res == 2) { //Bonus Malus cBonus++; add_array_object(&bonus, &object); clean_json_encoder(&object); } //Ajoute coord explosion add_integer(&coord, "x", x); add_integer(&coord, "y", y + 1 + i); add_array_object(&explosion, &coord); clean_json_encoder(&coord); break; } //Si un joueur if (player_collision_index(g, x, y + 1 + i, &index)) { if (index != playerIndex) pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]); if (g->player[index]->major == 0) { //Baisse la vie g->player[index]->life = g->player[index]->life - (g->player[index]->maxLife * (DAMAGEBOMB - (0.1 * i))); //Notification du joueur describe_player(g->player[index], ¬if); if (!notify_client(g->player[index]->cli, "POST", "attack/affect", ¬if)) { adderror("Impossible de notifer le client"); } clean_json_encoder(¬if); } if (index != playerIndex) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]); } //Si une bombe if (g->map[x][y + 1 + i] == '1' || g->map[x][y + 1 + i] == '2' || g->map[x][y + 1 + i] == '3') { cChain++; bomb_chain(g, playerIndex, x, y + 1 + i, &chain, &explosion); } //Si un mur solide if (g->map[x][y + 1 + i] == '-') { break; } //Ajoute coord explosion add_integer(&coord, "x", x); add_integer(&coord, "y", y + 1 + i); add_array_object(&explosion, &coord); clean_json_encoder(&coord); } else { break; } } //Vers la gauche for (int i = 0; i < 2 + g->player[playerIndex]->firePower; i++) { //Si on est dans la map if (x - 1 - i >= 0) { //Si un mur destructible if (g->map[x - 1 - i][y] == '*') { g->map[x - 1 - i][y] = '_'; res = spawn_object(g, x - 1 - i, y, &object); if (res == 1) { //Bombe cBomb++; add_array_object(&bomb, &object); clean_json_encoder(&object); } else if (res == 2) { //Bonus Malus cBonus++; add_array_object(&bonus, &object); clean_json_encoder(&object); } //Ajoute coord explosion add_integer(&coord, "x", x - 1 - i); add_integer(&coord, "y", y); add_array_object(&explosion, &coord); clean_json_encoder(&coord); break; } //Si un joueur if (player_collision_index(g, x - 1 - i, y, &index)) { if (index != playerIndex) pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]); if (g->player[index]->major == 0) { //Baisse la vie g->player[index]->life = g->player[index]->life - (g->player[index]->maxLife * (DAMAGEBOMB - (0.1 * i))); //Notification du joueur describe_player(g->player[index], ¬if); if (!notify_client(g->player[index]->cli, "POST", "attack/affect", ¬if)) { adderror("Impossible de notifer le client"); } clean_json_encoder(¬if); } if (index != playerIndex) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]); } //Si une bombe if (g->map[x - 1 - i][y] == '1' || g->map[x - 1 - i][y] == '2' || g->map[x - 1 - i][y] == '3') { cChain++; bomb_chain(g, playerIndex, x - 1 - i, y, &chain, &explosion); } //Si un mur solide if (g->map[x - 1 - i][y] == '-') { break; } //Ajoute coord explosion add_integer(&coord, "x", x - 1 - i); add_integer(&coord, "y", y); add_array_object(&explosion, &coord); clean_json_encoder(&coord); } else { break; } } //Vers la droite for (int i = 0; i < 2 + g->player[playerIndex]->firePower; i++) { //Si on est dans la map if (x + 1 + i >= 0) { //Si un mur destructible if (g->map[x + 1 + i][y] == '*') { g->map[x + 1 + i][y] = '_'; res = spawn_object(g, x + 1 + i, y, &object); if (res == 1) { //Bombe cBomb++; add_array_object(&bomb, &object); clean_json_encoder(&object); } else if (res == 2) { //Bonus Malus cBonus++; add_array_object(&bonus, &object); clean_json_encoder(&object); } //Ajoute coord explosion add_integer(&coord, "x", x + 1 + i); add_integer(&coord, "y", y); add_array_object(&explosion, &coord); clean_json_encoder(&coord); break; } //Si un joueur if (player_collision_index(g, x + 1 + i, y, &index)) { if (index != playerIndex) pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]); if (g->player[index]->major == 0) { //Baisse la vie g->player[index]->life = g->player[index]->life - (g->player[index]->maxLife * (DAMAGEBOMB - (0.1 * i))); //Notification du joueur describe_player(g->player[index], ¬if); if (!notify_client(g->player[index]->cli, "POST", "attack/affect", ¬if)) { adderror("Impossible de notifer le client"); } clean_json_encoder(¬if); } if (index != playerIndex) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]); } //Si une bombe if (g->map[x + 1 + i][y] == '1' || g->map[x + 1 + i][y] == '2' || g->map[x + 1 + i][y] == '3') { cChain++; bomb_chain(g, playerIndex, x + 1 + i, y, &chain, &explosion); } //Si un mur solide if (g->map[x + 1 + i][y] == '-') { break; } //Ajoute coord explosion add_integer(&coord, "x", x + 1 + i); add_integer(&coord, "y", y); add_array_object(&explosion, &coord); clean_json_encoder(&coord); } else { break; } } }//Si c'est une mine else { g->map[x][y] = '_'; //Calcul dommage if (g->player[playerIndex]->major == 0) { //Baisse la vie g->player[playerIndex]->life = g->player[playerIndex]->life - (g->player[playerIndex]->maxLife * DAMAGEMINE); //Notification du joueur describe_player(g->player[playerIndex], ¬if); if (!notify_client(g->player[playerIndex]->cli, "POST", "attack/affect", ¬if)) { adderror("Impossible de notifer le client"); } clean_json_encoder(¬if); } //Bas de bonus si mine add_boolean(json, "bonus", false); } //Affichage de la map free(g->mapContent); g->mapContent = unparse_map(g->map, g->width, g->height); add_string(json, "map", g->mapContent); //Ajout des json add_array(json, "bomb", &bomb); add_array(json, "bonusMalus", &bonus); add_array(json, "chain", &chain); add_array(json, "explosion", &explosion); //Nettoyage if (playerIndex >= 0) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]); pthread_mutex_unlock(&gameMutex[g->index]); clean_json_array(&bomb); clean_json_array(&bonus); clean_json_array(&chain); clean_json_array(&explosion); return true; } void bomb_chain(Game* g, int playerIndex, int x, int y, JsonArray* chain, JsonArray* explosion) { JsonEncoder json, notif, coord; int index; Player* p; obj_node* objn = NULL; //Inie json ini_encoder(&json); ini_encoder(¬if); ini_encoder(&coord); //Determine le type de la bombe switch (g->map[x][y]) { case '1': add_string(&json, "type", "classic"); p = search_player_object(g, OBJ_BCLASSIC, x, y); if (p != NULL) { p->classicBomb++; p->nbBomb--; objn = object_search(p->bomb, OBJ_BCLASSIC, x, y); object_delete(p->bomb, objn); } break; case '2': add_string(&json, "type", "mine"); p = search_player_object(g, OBJ_BMINE, x, y); if (p != NULL) { p->mine++; p->nbBomb--; objn = object_search(p->bomb, OBJ_BMINE, x, y); object_delete(p->bomb, objn); } break; case '3': add_string(&json, "type", "remote"); p = search_player_object(g, OBJ_BREMOTE, x, y); if (p != NULL) { p->remoteBomb++; p->nbBomb--; objn = object_search(p->bomb, OBJ_BREMOTE, x, y); object_delete(p->bomb, objn); } break; default: return; } //Determine la position de la bombe char pos[20]; memset(pos, 0, 20); snprintf(pos, 20, "%d,%d", x, y); add_string(&json, "pos", pos); //Calcul l'explosion non mine if (g->map[x][y] != '2') { g->map[x][y] = '_'; //Vers le haut for (int i = 0; i < 2; i++) { //Si on est dans la map if (y - 1 - i >= 0) { //Si un mur destructible if (g->map[x][y - 1 - i] == '*') { g->map[x][y - 1 - i] = '_'; //Ajoute coord explosion add_integer(&coord, "x", x); add_integer(&coord, "y", y - 1 - i); add_array_object(explosion, &coord); clean_json_encoder(&coord); break; } //Si un joueur if (player_collision_index(g, x, y - 1 - i, &index)) { if (index != playerIndex) pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]); if (g->player[index]->major == 0) { //Baisse la vie g->player[index]->life = g->player[index]->life - (g->player[index]->maxLife * (DAMAGEBOMB - (0.1 * i))); //Notification du joueur describe_player(g->player[index], ¬if); if (!notify_client(g->player[index]->cli, "POST", "attack/affect", ¬if)) { adderror("Impossible de notifer le client"); } clean_json_encoder(¬if); } if (index != playerIndex) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]); } //Si une bombe if (g->map[x][y - 1 - i] == '1' || g->map[x][y - 1 - i] == '2' || g->map[x][y - 1 - i] == '3') { bomb_chain(g, playerIndex, x, y - 1 - i, chain, explosion); } //Si un mur solide if (g->map[x][y - 1 - i] == '-') { break; } //Ajoute coord explosion add_integer(&coord, "x", x); add_integer(&coord, "y", y - 1 - i); add_array_object(explosion, &coord); clean_json_encoder(&coord); } else { break; } } //Vers le bas for (int i = 0; i < 2 + g->player[playerIndex]->firePower; i++) { //Si on est dans la map if (y + 1 + i <= g->height) { //Si un mur destructible if (g->map[x][y + 1 + i] == '*') { g->map[x][y + 1 + i] = '_'; //Ajoute coord explosion add_integer(&coord, "x", x); add_integer(&coord, "y", y + 1 + i); add_array_object(explosion, &coord); clean_json_encoder(&coord); break; } //Si un joueur if (player_collision_index(g, x, y + 1 + i, &index)) { if (index != playerIndex) pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]); if (g->player[index]->major == 0) { //Baisse la vie g->player[index]->life = g->player[index]->life - (g->player[index]->maxLife * (DAMAGEBOMB - (0.1 * i))); //Notification du joueur describe_player(g->player[index], ¬if); if (!notify_client(g->player[index]->cli, "POST", "attack/affect", ¬if)) { adderror("Impossible de notifer le client"); } clean_json_encoder(¬if); } if (index != playerIndex) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]); } //Si une bombe if (g->map[x][y + 1 + i] == '1' || g->map[x][y + 1 + i] == '2' || g->map[x][y + 1 + i] == '3') { bomb_chain(g, playerIndex, x, y + 1 + i, chain, explosion); } //Si un mur solide if (g->map[x][y + 1 + i] == '-') { break; } //Ajoute coord explosion add_integer(&coord, "x", x); add_integer(&coord, "y", y + 1 + i); add_array_object(explosion, &coord); clean_json_encoder(&coord); } else { break; } } //Vers la gauche for (int i = 0; i < 2 + g->player[playerIndex]->firePower; i++) { //Si on est dans la map if (x - 1 - i >= 0) { //Si un mur destructible if (g->map[x - 1 - i][y] == '*') { g->map[x - 1 - i][y] = '_'; //Ajoute coord explosion add_integer(&coord, "x", x - 1 - i); add_integer(&coord, "y", y); add_array_object(explosion, &coord); clean_json_encoder(&coord); break; } //Si un joueur if (player_collision_index(g, x - 1 - i, y, &index)) { if (index != playerIndex) pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]); if (g->player[index]->major == 0) { //Baisse la vie g->player[index]->life = g->player[index]->life - (g->player[index]->maxLife * (DAMAGEBOMB - (0.1 * i))); //Notification du joueur describe_player(g->player[index], ¬if); if (!notify_client(g->player[index]->cli, "POST", "attack/affect", ¬if)) { adderror("Impossible de notifer le client"); } clean_json_encoder(¬if); } if (index != playerIndex) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]); } //Si une bombe if (g->map[x - 1 - i][y] == '1' || g->map[x - 1 - i][y] == '2' || g->map[x - 1 - i][y] == '3') { bomb_chain(g, playerIndex, x - 1 - i, y, chain, explosion); } //Si un mur solide if (g->map[x - 1 - i][y] == '-') { break; } //Ajoute coord explosion add_integer(&coord, "x", x - 1 - i); add_integer(&coord, "y", y); add_array_object(explosion, &coord); clean_json_encoder(&coord); } else { break; } } //Vers la droite for (int i = 0; i < 2 + g->player[playerIndex]->firePower; i++) { //Si on est dans la map if (x + 1 + i >= 0) { //Si un mur destructible if (g->map[x + 1 + i][y] == '*') { g->map[x + 1 + i][y] = '_'; //Ajoute coord explosion add_integer(&coord, "x", x + 1 + i); add_integer(&coord, "y", y); add_array_object(explosion, &coord); clean_json_encoder(&coord); break; } //Si un joueur if (player_collision_index(g, x + 1 + i, y, &index)) { if (index != playerIndex) pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]); if (g->player[index]->major == 0) { //Baisse la vie g->player[index]->life = g->player[index]->life - (g->player[index]->maxLife * (DAMAGEBOMB - (0.1 * i))); //Notification du joueur describe_player(g->player[index], ¬if); if (!notify_client(g->player[index]->cli, "POST", "attack/affect", ¬if)) { adderror("Impossible de notifer le client"); } clean_json_encoder(¬if); } if (index != playerIndex) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]); } //Si une bombe if (g->map[x + 1 + i][y] == '1' || g->map[x + 1 + i][y] == '2' || g->map[x + 1 + i][y] == '3') { bomb_chain(g, playerIndex, x + 1 + i, y, chain, explosion); } //Si un mur solide if (g->map[x + 1 + i][y] == '-') { break; } //Ajoute coord explosion add_integer(&coord, "x", x + 1 + i); add_integer(&coord, "y", y); add_array_object(explosion, &coord); clean_json_encoder(&coord); } else { break; } } }//Si c'est une mine else { g->map[x][y] = '_'; //Recup le joueur if (player_collision_index(g, x, y, &index)) { if (index != playerIndex) pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]); if (g->player[index]->major == 0) { //Baisse la vie g->player[index]->life = g->player[index]->life - (g->player[index]->maxLife * DAMAGEMINE); //Notification du joueur describe_player(g->player[index], ¬if); if (!notify_client(g->player[index]->cli, "POST", "attack/affect", ¬if)) { adderror("Impossible de notifer le client"); } clean_json_encoder(¬if); } if (index != playerIndex) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]); } } //Ajoute json dans le tableau add_array_object(chain, &json); //Nettoyage clean_json_encoder(&json); } int spawn_object(Game* g, int x, int y, JsonEncoder* json) { int random, res = 0; //Generation random si spawn ou non srand(time(NULL)); random = rand() % 100 + 1; if (random > SPAWNRATE) { return 0; //Pas de spawn } //Choisit l'objet random = rand() % 11; switch (random) { case OBJ_BCLASSIC: res = 1; add_string(json, "type", "classic"); break; case OBJ_BMINE: res = 1; add_string(json, "type", "mine"); break; case OBJ_BREMOTE: res = 1; add_string(json, "type", "remote"); break; case OBJ_BOMBUP: res = 2; add_string(json, "type", "bomb_up"); break; case OBJ_BOMBDOWN: res = 2; add_string(json, "type", "bomb_down"); break; case OBJ_FIREPOWER: res = 2; add_string(json, "type", "fire_power"); break; case OBJ_SCOOTER: res = 2; add_string(json, "type", "scooter"); break; case OBJ_BROKENLEG: res = 2; add_string(json, "type", "broken_legs"); break; case OBJ_LIFEUP: res = 2; add_string(json, "type", "life_up"); break; case OBJ_LIFEMAX: res = 2; add_string(json, "type", "life_max"); break; case OBJ_MAJOR: res = 2; add_string(json, "type", "major"); break; } //Ajoute l'objet dans la partie object_add(g->object, random, x, y); //Ajoute postion au json char pos[20]; memset(pos, 0, 20); snprintf(pos, 20, "%d,%d", x, y); add_string(json, "pos", pos); //Retourne type d'ajout return res; } void remove_player(Game* g, int playerIndex) { pthread_mutex_lock(&gameMutex[g->index]); pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]); g->nbPlayer--; delete_player(g->player[playerIndex]); pthread_mutex_unlock(&gameMutex[g->index]); pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]); } void stop_game(Game* g) { pthread_mutex_lock(&gameMutex[g->index]); //Indique comme inactive g->active = false; //Suppr les joueurs for (int i = 0; i < MAXPLAYER; i++) { //pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + i]); if (g->player[i]->ini) { delete_player(g->player[i]); } free(g->player[i]); //pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]); } //Libere la memoire object_clean(g->object); free(g->object); for (int i = 0; i < g->width; i++) { free(g->map[i]); } free(g->map); free(g->mapName); free(g->mapContent); pthread_mutex_unlock(&gameMutex[g->index]); //Retire une game nbGame--; } void clean_games() { for (int i = 0; i < MAXGAME; i++) { if (game[i].active) { pthread_mutex_unlock(&gameMutex[i]); stop_game(&game[i]); } } }