game.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913
  1. /*
  2. * File: game.c
  3. * Author: Arthur Brandao
  4. *
  5. * Created on 28 novembre 2018
  6. */
  7. #define _XOPEN_SOURCE 500
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include "error.h"
  11. #include "str.h"
  12. #include "file.h"
  13. #include "game.h"
  14. #include "bomberstudent_server.h"
  15. /* --- Extern --- */
  16. Game game[MAXGAME];
  17. int nbGame = 0;
  18. pthread_mutex_t gameMutex[MAXGAME];
  19. pthread_mutex_t playerMutex[MAXGAME * MAXPLAYER];
  20. /* --- Fonctions privées --- */
  21. /**
  22. * Transforme le fichier map en un tableau 2D
  23. * @param char* Le contenu du fichier map
  24. * @param int Largeur de la map
  25. * @param int Hauteur de la map
  26. * @return char** La map parser
  27. */
  28. char** parse_map(char* mapContent, int width, int height) {
  29. char** map = malloc(sizeof (char*) * width);
  30. //Creation des colonnes
  31. for (int i = 0; i < width; i++) {
  32. map[i] = malloc(sizeof (char) * height);
  33. }
  34. //Remplissage
  35. for (int i = 0; i < height; i++) {
  36. for (int j = 0; j < width; j++) {
  37. map[j][i] = *mapContent;
  38. mapContent++;
  39. }
  40. mapContent++;
  41. }
  42. return map;
  43. }
  44. /**
  45. * Transforme un tableau 2D en une chaine
  46. * @param char** Le contenu du fichier map
  47. * @param int Largeur de la map
  48. * @param int Hauteur de la map
  49. * @return char* La map
  50. */
  51. char* unparse_map(char** map, int width, int height) {
  52. int pos = 0;
  53. char* mapContent = malloc(sizeof (char) * (width * height + 1));
  54. memset(mapContent, 0, width * height + 1);
  55. //Remplissage
  56. for (int i = 0; i < height; i++) {
  57. for (int j = 0; j < width; j++) {
  58. mapContent[pos++] = map[j][i];
  59. }
  60. }
  61. return mapContent;
  62. }
  63. /* --- Fonctions publiques --- */
  64. boolean ini_games() {
  65. //Ini les games
  66. for (int i = 0; i < MAXGAME; i++) {
  67. game[i].active = false;
  68. game[i].index = i;
  69. }
  70. //Ini les mutex des games
  71. for (int i = 0; i < MAXGAME; i++) {
  72. if (pthread_mutex_init(&gameMutex[i], NULL) != 0) {
  73. adderror("Impossible d'initialiser les mutex des games");
  74. return false;
  75. }
  76. }
  77. //Ini les mutex des joueurs des games
  78. for (int i = 0; i < MAXGAME * MAXPLAYER; i++) {
  79. if (pthread_mutex_init(&playerMutex[i], NULL) != 0) {
  80. adderror("Impossible d'initialiser les mutex des joueurs");
  81. return false;
  82. }
  83. }
  84. return true;
  85. }
  86. void list_map(JsonArray* res) {
  87. char** result;
  88. int nbResult;
  89. //Regarde les fichiers dans le dossier
  90. result = file_list(MAPDIR, &nbResult);
  91. for (int i = 0; i < nbResult; i++) {
  92. add_array_string(res, result[i]);
  93. free(result[i]);
  94. }
  95. free(result);
  96. }
  97. int list_game(JsonArray* res) {
  98. JsonEncoder gameJson;
  99. int compteur = 0, i = 0;
  100. //Si il n' y a aucune game
  101. if (nbGame == 0) {
  102. return 0;
  103. }
  104. //Initialisation json
  105. ini_encoder(&gameJson);
  106. //Ajoute chaque game
  107. while (compteur < nbGame && i < MAXGAME) {
  108. pthread_mutex_lock(&gameMutex[i]);
  109. if (!game[i].active) {
  110. pthread_mutex_unlock(&gameMutex[i]);
  111. i++;
  112. continue;
  113. }
  114. //Creation objet json
  115. add_string(&gameJson, "name", game[i].name);
  116. add_integer(&gameJson, "nbPlayer", game[i].nbPlayer);
  117. add_string(&gameJson, "map", game[i].mapName);
  118. //Ajout dans le tableau
  119. add_array_object(res, &gameJson);
  120. //Nettoyage encoder objet
  121. clean_json_encoder(&gameJson);
  122. //Incremente
  123. pthread_mutex_unlock(&gameMutex[i]);
  124. i++;
  125. compteur++;
  126. }
  127. return nbGame;
  128. }
  129. int* map_size(char* map) {
  130. int* res;
  131. res = malloc(sizeof (int) * 2);
  132. res[WIDTH] = 0;
  133. res[HEIGHT] = 1;
  134. //Parcours la 1er ligne pour compter le nombre de caractère
  135. while (*map != '\n' && *map != '\0') {
  136. res[WIDTH]++;
  137. map++;
  138. }
  139. if (*map == '\0') {
  140. return res;
  141. }
  142. //Compte les lignes
  143. map++;
  144. while (*map != '\0') {
  145. if (*map == '\n') {
  146. res[HEIGHT]++;
  147. }
  148. map++;
  149. }
  150. return res;
  151. }
  152. int create_game(char* name, char* map) {
  153. int length, index = 0;
  154. char* path;
  155. int* size;
  156. //Regarde si il reste une game de disponnible
  157. if (nbGame == MAXGAME) {
  158. return ERR;
  159. }
  160. //Cherche une game libre
  161. while (index < MAXGAME) {
  162. pthread_mutex_lock(&gameMutex[index]);
  163. if (game[index].active == false) {
  164. break;
  165. }
  166. pthread_mutex_unlock(&gameMutex[index]);
  167. index++;
  168. }
  169. //Recup la map
  170. length = strlen(MAPDIR) + strlen(map);
  171. path = new_string(length);
  172. snprintf(path, length + 1, "%s%s", MAPDIR, map);
  173. game[index].mapContent = file_get_content(path);
  174. //Calcul taille de la map
  175. size = map_size(game[index].mapContent);
  176. //Set Up
  177. game[index].active = true;
  178. game[index].name = string_copy(name);
  179. game[index].nbPlayer = 0;
  180. game[index].mapName = string_copy(map);
  181. game[index].width = size[WIDTH];
  182. game[index].height = size[HEIGHT];
  183. game[index].map = parse_map(game[index].mapContent, size[WIDTH], size[HEIGHT]);
  184. for (int i = 0; i < MAXPLAYER; i++) {
  185. game[index].player[i] = malloc(sizeof (Player));
  186. game[index].player[i]->ini = false;
  187. }
  188. game[index].object = malloc(sizeof (Object));
  189. object_ini(game[index].object);
  190. //object_add(game[index].object, OBJ_MAJOR, 1, 1);
  191. pthread_mutex_unlock(&gameMutex[index]);
  192. //Retourne la position de la partie dans le tableau
  193. nbGame++;
  194. free(path);
  195. free(size);
  196. return index;
  197. }
  198. int add_player(Game* g, int cliId) {
  199. int index = 0;
  200. Client* cli;
  201. //Verif que la game n'est pas deja pleine
  202. pthread_mutex_lock(&gameMutex[g->index]);
  203. if (g->nbPlayer >= MAXPLAYER) {
  204. pthread_mutex_unlock(&gameMutex[g->index]);
  205. return ERR;
  206. }
  207. //Cherche un joueur non initialisé
  208. while (index < MAXPLAYER) {
  209. pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]);
  210. if (!g->player[index]->ini) {
  211. break;
  212. }
  213. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]);
  214. index++;
  215. }
  216. //Recup du client
  217. cli = get_client(cliId);
  218. if (cli == NULL) {
  219. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]);
  220. pthread_mutex_unlock(&gameMutex[g->index]);
  221. return ERR;
  222. }
  223. //Creation du joueur
  224. create_player(g->player[index], cli);
  225. g->nbPlayer++;
  226. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]);
  227. pthread_mutex_unlock(&gameMutex[g->index]);
  228. return index;
  229. }
  230. void describe_game(Game* g, int playerIndex, JsonEncoder* desc) {
  231. JsonEncoder player;
  232. JsonEncoder map;
  233. JsonArray players;
  234. char* content;
  235. //Initialisation
  236. ini_encoder(&player);
  237. ini_encoder(&map);
  238. ini_array_encoder(&players);
  239. //Info map
  240. pthread_mutex_lock(&gameMutex[g->index]);
  241. content = remove_char(g->mapContent, '\n'); //La map sans \n car interdit en JSON
  242. add_integer(&map, "width", g->width);
  243. add_integer(&map, "height", g->height);
  244. add_string(&map, "content", content);
  245. free(content);
  246. //Ajout info
  247. add_integer(desc, "nbPlayers", g->nbPlayer);
  248. add_object(desc, "map", &map);
  249. //Ajout info courte joueur
  250. //printf("Add players\n");
  251. for (int i = 0; i < MAXPLAYER; i++) {
  252. pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + i]);
  253. if (g->player[i]->ini) {
  254. describe_short_player(g->player[i], &player);
  255. add_array_object(&players, &player);
  256. clean_json_encoder(&player);
  257. }
  258. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]);
  259. }
  260. //printf("Fin Add players\n");
  261. add_array(desc, "players", &players);
  262. //Si besoins ajout un joueur
  263. if (playerIndex >= 0 && playerIndex < MAXPLAYER) {
  264. pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]);
  265. if (g->player[playerIndex]->ini) {
  266. describe_player(g->player[playerIndex], &player);
  267. add_object(desc, "player", &player);
  268. clean_json_encoder(&player);
  269. }
  270. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]);
  271. }
  272. //Nettoyage
  273. pthread_mutex_unlock(&gameMutex[g->index]);
  274. clean_json_encoder(&map);
  275. clean_json_array(&players);
  276. }
  277. boolean notify_player(Game* g, char* method, char* ressource, JsonEncoder* param, int excludePlayerId) {
  278. boolean res = true;
  279. pthread_mutex_lock(&gameMutex[g->index]);
  280. //Regarde si la game est active
  281. if (!g->active) {
  282. pthread_mutex_unlock(&gameMutex[g->index]);
  283. return false;
  284. }
  285. //Parcours les joeurs de la game
  286. for (int i = 0; i < MAXPLAYER; i++) {
  287. //Si joueur actif
  288. pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + i]);
  289. if (g->player[i]->ini && g->player[i]->id != excludePlayerId) {
  290. res = res && notify_client(g->player[i]->cli, method, ressource, param);
  291. }
  292. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]);
  293. }
  294. pthread_mutex_unlock(&gameMutex[g->index]);
  295. return res;
  296. }
  297. boolean player_collision(Game* g, int x, int y) {
  298. for (int i = 0; i < MAXPLAYER; i++) {
  299. if (g->player[i]->ini) {
  300. if (g->player[i]->x == x && g->player[i]->y == y) {
  301. return true;
  302. }
  303. }
  304. }
  305. return false;
  306. }
  307. boolean player_collision_index(Game* g, int x, int y, int* index) {
  308. for (int i = 0; i < MAXPLAYER; i++) {
  309. if (g->player[i]->ini) {
  310. if (g->player[i]->x == x && g->player[i]->y == y) {
  311. *index = i;
  312. return true;
  313. }
  314. }
  315. }
  316. return false;
  317. }
  318. boolean bomb_explode(Game* g, int playerIndex, int x, int y, JsonEncoder* json) {
  319. JsonEncoder object, notif;
  320. JsonArray bomb, bonus, chain;
  321. int res, index, cBomb = 0, cBonus = 0, cChain = 0;
  322. char* map;
  323. //Inie json
  324. ini_encoder(&object);
  325. ini_encoder(&notif);
  326. ini_array_encoder(&bomb);
  327. ini_array_encoder(&bonus);
  328. ini_array_encoder(&chain);
  329. //Mutex
  330. pthread_mutex_lock(&gameMutex[g->index]);
  331. if(playerIndex >= 0) pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]);
  332. //Determine le type de la bombe
  333. switch (g->map[x][y]) {
  334. case '1':
  335. add_string(json, "type", "classic");
  336. g->player[playerIndex]->classicBomb++;
  337. break;
  338. case '2':
  339. add_string(json, "type", "mine");
  340. g->player[playerIndex]->mine++;
  341. break;
  342. case '3':
  343. add_string(json, "type", "remote");
  344. g->player[playerIndex]->remoteBomb++;
  345. break;
  346. default:
  347. if(playerIndex >= 0) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]);
  348. pthread_mutex_unlock(&gameMutex[g->index]);
  349. return false;
  350. }
  351. //Determine la position de la bombe
  352. char pos[20];
  353. memset(pos, 0, 20);
  354. snprintf(pos, 20, "%d,%d", x, y);
  355. add_string(json, "pos", pos);
  356. //Calcul l'explosion non mine
  357. if (g->map[x][y] != '2') {
  358. g->map[x][y] = '_';
  359. //Si le joueur à un bonus
  360. if (g->player[playerIndex]->firePower > 0) {
  361. add_boolean(json, "bonus", true);
  362. } else {
  363. add_boolean(json, "bonus", false);
  364. }
  365. //Vers le haut
  366. for (int i = 0; i < 2 + g->player[playerIndex]->firePower; i++) {
  367. //Si on est dans la map
  368. if (y - 1 - i >= 0) {
  369. //Si un mur destructible
  370. if (g->map[x][y - 1 - i] == '*') {
  371. g->map[x][y - 1 - i] = '_';
  372. res = spawn_object(g, x, y - 1 - i, &object);
  373. if (res == 1) { //Bombe
  374. cBomb++;
  375. add_array_object(&bomb, &object);
  376. clean_json_encoder(&object);
  377. } else if (res == 2) { //Bonus Malus
  378. cBonus++;
  379. add_array_object(&bonus, &object);
  380. clean_json_encoder(&object);
  381. }
  382. break;
  383. }
  384. //Si un joueur
  385. if (player_collision_index(g, x, y - 1 - i, &index)) {
  386. if (index != playerIndex) pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]);
  387. if (g->player[index]->major == 0) {
  388. //Baisse la vie
  389. g->player[index]->life = g->player[index]->life - (g->player[index]->maxLife * (DAMAGEBOMB - (0.1 * i)));
  390. //Notification du joueur
  391. describe_player(g->player[index], &notif);
  392. if (!notify_client(g->player[index]->cli, "POST", "attack/affect", &notif)) {
  393. adderror("Impossible de notifer le client");
  394. }
  395. clean_json_encoder(&notif);
  396. }
  397. if (index != playerIndex) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]);
  398. }
  399. //Si une bombe
  400. if (g->map[x][y - 1 - i] == '1' || g->map[x][y - 1 - i] == '2' || g->map[x][y - 1 - i] == '3') {
  401. cChain++;
  402. bomb_chain(g, playerIndex, x, y - 1 - i, &chain);
  403. }
  404. //Si un mur solide
  405. if(g->map[x][y - 1 - i] == '-'){
  406. break;
  407. }
  408. } else {
  409. break;
  410. }
  411. }
  412. //Vers le bas
  413. for (int i = 0; i < 2 + g->player[playerIndex]->firePower; i++) {
  414. //Si on est dans la map
  415. if (y + 1 + i <= g->height) {
  416. //Si un mur destructible
  417. if (g->map[x][y + 1 + i] == '*') {
  418. g->map[x][y + 1 + i] = '_';
  419. res = spawn_object(g, x, y + 1 + i, &object);
  420. if (res == 1) { //Bombe
  421. cBomb++;
  422. add_array_object(&bomb, &object);
  423. clean_json_encoder(&object);
  424. } else if (res == 2) { //Bonus Malus
  425. cBonus++;
  426. add_array_object(&bonus, &object);
  427. clean_json_encoder(&object);
  428. }
  429. break;
  430. }
  431. //Si un joueur
  432. if (player_collision_index(g, x, y + 1 + i, &index)) {
  433. if (index != playerIndex) pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]);
  434. if (g->player[index]->major == 0) {
  435. //Baisse la vie
  436. g->player[index]->life = g->player[index]->life - (g->player[index]->maxLife * (DAMAGEBOMB - (0.1 * i)));
  437. //Notification du joueur
  438. describe_player(g->player[index], &notif);
  439. if (!notify_client(g->player[index]->cli, "POST", "attack/affect", &notif)) {
  440. adderror("Impossible de notifer le client");
  441. }
  442. clean_json_encoder(&notif);
  443. }
  444. if (index != playerIndex) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]);
  445. }
  446. //Si une bombe
  447. if (g->map[x][y + 1 + i] == '1' || g->map[x][y + 1 + i] == '2' || g->map[x][y + 1 + i] == '3') {
  448. cChain++;
  449. bomb_chain(g, playerIndex, x, y + 1 + i, &chain);
  450. }
  451. //Si un mur solide
  452. if(g->map[x][y + 1 + i] == '-'){
  453. break;
  454. }
  455. } else {
  456. break;
  457. }
  458. }
  459. //Vers la gauche
  460. for (int i = 0; i < 2 + g->player[playerIndex]->firePower; i++) {
  461. //Si on est dans la map
  462. if (x - 1 - i >= 0) {
  463. //Si un mur destructible
  464. if (g->map[x - 1 - i][y] == '*') {
  465. g->map[x - 1 - i][y] = '_';
  466. res = spawn_object(g, x - 1 - i, y, &object);
  467. if (res == 1) { //Bombe
  468. cBomb++;
  469. add_array_object(&bomb, &object);
  470. clean_json_encoder(&object);
  471. } else if (res == 2) { //Bonus Malus
  472. cBonus++;
  473. add_array_object(&bonus, &object);
  474. clean_json_encoder(&object);
  475. }
  476. break;
  477. }
  478. //Si un joueur
  479. if (player_collision_index(g, x - 1 - i, y, &index)) {
  480. if (index != playerIndex) pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]);
  481. if (g->player[index]->major == 0) {
  482. //Baisse la vie
  483. g->player[index]->life = g->player[index]->life - (g->player[index]->maxLife * (DAMAGEBOMB - (0.1 * i)));
  484. //Notification du joueur
  485. describe_player(g->player[index], &notif);
  486. if (!notify_client(g->player[index]->cli, "POST", "attack/affect", &notif)) {
  487. adderror("Impossible de notifer le client");
  488. }
  489. clean_json_encoder(&notif);
  490. }
  491. if (index != playerIndex) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]);
  492. }
  493. //Si une bombe
  494. if (g->map[x - 1 - i][y] == '1' || g->map[x - 1 - i][y] == '2' || g->map[x - 1 - i][y] == '3') {
  495. cChain++;
  496. bomb_chain(g, playerIndex, x - 1 - i, y, &chain);
  497. }
  498. //Si un mur solide
  499. if(g->map[x - 1 - i][y] == '-'){
  500. break;
  501. }
  502. } else {
  503. break;
  504. }
  505. }
  506. //Vers la droite
  507. for (int i = 0; i < 2 + g->player[playerIndex]->firePower; i++) {
  508. //Si on est dans la map
  509. if (x + 1 + i >= 0) {
  510. //Si un mur destructible
  511. if (g->map[x + 1 + i][y] == '*') {
  512. g->map[x + 1 + i][y] = '_';
  513. res = spawn_object(g, x + 1 + i, y, &object);
  514. if (res == 1) { //Bombe
  515. cBomb++;
  516. add_array_object(&bomb, &object);
  517. clean_json_encoder(&object);
  518. } else if (res == 2) { //Bonus Malus
  519. cBonus++;
  520. add_array_object(&bonus, &object);
  521. clean_json_encoder(&object);
  522. }
  523. break;
  524. }
  525. //Si un joueur
  526. if (player_collision_index(g, x + 1 + i, y, &index)) {
  527. if (index != playerIndex) pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]);
  528. if (g->player[index]->major == 0) {
  529. //Baisse la vie
  530. g->player[index]->life = g->player[index]->life - (g->player[index]->maxLife * (DAMAGEBOMB - (0.1 * i)));
  531. //Notification du joueur
  532. describe_player(g->player[index], &notif);
  533. if (!notify_client(g->player[index]->cli, "POST", "attack/affect", &notif)) {
  534. adderror("Impossible de notifer le client");
  535. }
  536. clean_json_encoder(&notif);
  537. }
  538. if (index != playerIndex) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]);
  539. }
  540. //Si une bombe
  541. if (g->map[x + 1 + i][y] == '1' || g->map[x + 1 + i][y] == '2' || g->map[x + 1 + i][y] == '3') {
  542. cChain++;
  543. bomb_chain(g, playerIndex, x + 1 + i, y, &chain);
  544. }
  545. //Si un mur solide
  546. if(g->map[x + 1 + i][y] == '-'){
  547. break;
  548. }
  549. } else {
  550. break;
  551. }
  552. }
  553. }
  554. //Si c'est une mine
  555. else {
  556. g->map[x][y] = '_';
  557. //Pas de bonus pour une mine
  558. add_boolean(json, "bonus", false);
  559. //Recup le joueur
  560. if (player_collision_index(g, x, y, &index)) {
  561. if (index != playerIndex) pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]);
  562. if (g->player[index]->major == 0) {
  563. //Baisse la vie
  564. g->player[index]->life = g->player[index]->life - (g->player[index]->maxLife * DAMAGEMINE);
  565. //Notification du joueur
  566. describe_player(g->player[index], &notif);
  567. if (!notify_client(g->player[index]->cli, "POST", "attack/affect", &notif)) {
  568. adderror("Impossible de notifer le client");
  569. }
  570. clean_json_encoder(&notif);
  571. }
  572. if (index != playerIndex) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]);
  573. }
  574. }
  575. //Affichage de la map
  576. map = unparse_map(g->map, g->width, g->height);
  577. add_string(json, "map", map);
  578. //Ajout des json
  579. add_array(json, "bomb", &bomb);
  580. add_array(json, "bonusMalus", &bonus);
  581. add_array(json, "chain", &chain);
  582. //Nettoyage
  583. if(playerIndex >= 0) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]);
  584. pthread_mutex_unlock(&gameMutex[g->index]);
  585. free(map);
  586. return true;
  587. }
  588. void bomb_chain(Game* g, int playerIndex, int x, int y, JsonArray* chain) {
  589. JsonEncoder json, notif;
  590. int index;
  591. //Inie json
  592. ini_encoder(&json);
  593. ini_encoder(&notif);
  594. //Determine le type de la bombe
  595. switch (g->map[x][y]) {
  596. case '1':
  597. add_string(&json, "type", "classic");
  598. break;
  599. case '2':
  600. add_string(&json, "type", "mine");
  601. break;
  602. case '3':
  603. add_string(&json, "type", "remote");
  604. break;
  605. default:
  606. return;
  607. }
  608. //Determine la position de la bombe
  609. char pos[20];
  610. memset(pos, 0, 20);
  611. snprintf(pos, 20, "%d,%d", x, y);
  612. add_string(&json, "pos", pos);
  613. //Calcul l'explosion non mine
  614. if (g->map[x][y] != '2') {
  615. g->map[x][y] = '_';
  616. //Vers le haut
  617. for (int i = 0; i < 2; i++) {
  618. //Si on est dans la map
  619. if (y - 1 - i >= 0) {
  620. //Si un mur destructible
  621. if (g->map[x][y - 1 - i] == '*') {
  622. g->map[x][y - 1 - i] = '_';
  623. break;
  624. }
  625. //Si un joueur
  626. if (player_collision_index(g, x, y - 1 - i, &index)) {
  627. if (index != playerIndex) pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]);
  628. if (g->player[index]->major == 0) {
  629. //Baisse la vie
  630. g->player[index]->life = g->player[index]->life - (g->player[index]->maxLife * (DAMAGEBOMB - (0.1 * i)));
  631. //Notification du joueur
  632. describe_player(g->player[index], &notif);
  633. if (!notify_client(g->player[index]->cli, "POST", "attack/affect", &notif)) {
  634. adderror("Impossible de notifer le client");
  635. }
  636. clean_json_encoder(&notif);
  637. }
  638. if (index != playerIndex) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]);
  639. }
  640. //Si une bombe
  641. if (g->map[x][y - 1 - i] == '1' || g->map[x][y - 1 - i] == '2' || g->map[x][y - 1 - i] == '3') {
  642. bomb_chain(g, playerIndex, x, y - 1 - i, chain);
  643. }
  644. //Si un mur solide
  645. if(g->map[x][y - 1 - i] == '-'){
  646. break;
  647. }
  648. } else {
  649. break;
  650. }
  651. }
  652. //Vers le bas
  653. for (int i = 0; i < 2 + g->player[playerIndex]->firePower; i++) {
  654. //Si on est dans la map
  655. if (y + 1 + i <= g->height) {
  656. //Si un mur destructible
  657. if (g->map[x][y + 1 + i] == '*') {
  658. g->map[x][y + 1 + i] = '_';
  659. break;
  660. }
  661. //Si un joueur
  662. if (player_collision_index(g, x, y + 1 + i, &index)) {
  663. if (index != playerIndex) pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]);
  664. if (g->player[index]->major == 0) {
  665. //Baisse la vie
  666. g->player[index]->life = g->player[index]->life - (g->player[index]->maxLife * (DAMAGEBOMB - (0.1 * i)));
  667. //Notification du joueur
  668. describe_player(g->player[index], &notif);
  669. if (!notify_client(g->player[index]->cli, "POST", "attack/affect", &notif)) {
  670. adderror("Impossible de notifer le client");
  671. }
  672. clean_json_encoder(&notif);
  673. }
  674. if (index != playerIndex) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]);
  675. }
  676. //Si une bombe
  677. if (g->map[x][y + 1 + i] == '1' || g->map[x][y + 1 + i] == '2' || g->map[x][y + 1 + i] == '3') {
  678. bomb_chain(g, playerIndex, x, y + 1 + i, chain);
  679. }
  680. //Si un mur solide
  681. if(g->map[x][y + 1 + i] == '-'){
  682. break;
  683. }
  684. } else {
  685. break;
  686. }
  687. }
  688. //Vers la gauche
  689. for (int i = 0; i < 2 + g->player[playerIndex]->firePower; i++) {
  690. //Si on est dans la map
  691. if (x - 1 - i >= 0) {
  692. //Si un mur destructible
  693. if (g->map[x - 1 - i][y] == '*') {
  694. g->map[x - 1 - i][y] = '_';
  695. break;
  696. }
  697. //Si un joueur
  698. if (player_collision_index(g, x - 1 - i, y, &index)) {
  699. if (index != playerIndex) pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]);
  700. if (g->player[index]->major == 0) {
  701. //Baisse la vie
  702. g->player[index]->life = g->player[index]->life - (g->player[index]->maxLife * (DAMAGEBOMB - (0.1 * i)));
  703. //Notification du joueur
  704. describe_player(g->player[index], &notif);
  705. if (!notify_client(g->player[index]->cli, "POST", "attack/affect", &notif)) {
  706. adderror("Impossible de notifer le client");
  707. }
  708. clean_json_encoder(&notif);
  709. }
  710. if (index != playerIndex) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]);
  711. }
  712. //Si une bombe
  713. if (g->map[x - 1 - i][y] == '1' || g->map[x - 1 - i][y] == '2' || g->map[x - 1 - i][y] == '3') {
  714. bomb_chain(g, playerIndex, x - 1 - i, y, chain);
  715. }
  716. //Si un mur solide
  717. if(g->map[x - 1 - i][y] == '-'){
  718. break;
  719. }
  720. } else {
  721. break;
  722. }
  723. }
  724. //Vers la droite
  725. for (int i = 0; i < 2 + g->player[playerIndex]->firePower; i++) {
  726. //Si on est dans la map
  727. if (x + 1 + i >= 0) {
  728. //Si un mur destructible
  729. if (g->map[x + 1 + i][y] == '*') {
  730. g->map[x + 1 + i][y] = '_';
  731. break;
  732. }
  733. //Si un joueur
  734. if (player_collision_index(g, x + 1 + i, y, &index)) {
  735. if (index != playerIndex) pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]);
  736. if (g->player[index]->major == 0) {
  737. //Baisse la vie
  738. g->player[index]->life = g->player[index]->life - (g->player[index]->maxLife * (DAMAGEBOMB - (0.1 * i)));
  739. //Notification du joueur
  740. describe_player(g->player[index], &notif);
  741. if (!notify_client(g->player[index]->cli, "POST", "attack/affect", &notif)) {
  742. adderror("Impossible de notifer le client");
  743. }
  744. clean_json_encoder(&notif);
  745. }
  746. if (index != playerIndex) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]);
  747. }
  748. //Si une bombe
  749. if (g->map[x + 1 + i][y] == '1' || g->map[x + 1 + i][y] == '2' || g->map[x + 1 + i][y] == '3') {
  750. bomb_chain(g, playerIndex, x + 1 + i, y, chain);
  751. }
  752. //Si un mur solide
  753. if(g->map[x + 1 + i][y] == '-'){
  754. break;
  755. }
  756. } else {
  757. break;
  758. }
  759. }
  760. }
  761. //Si c'est une mine
  762. else {
  763. g->map[x][y] = '_';
  764. //Recup le joueur
  765. if (player_collision_index(g, x, y, &index)) {
  766. if (index != playerIndex) pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]);
  767. if (g->player[index]->major == 0) {
  768. //Baisse la vie
  769. g->player[index]->life = g->player[index]->life - (g->player[index]->maxLife * DAMAGEMINE);
  770. //Notification du joueur
  771. describe_player(g->player[index], &notif);
  772. if (!notify_client(g->player[index]->cli, "POST", "attack/affect", &notif)) {
  773. adderror("Impossible de notifer le client");
  774. }
  775. clean_json_encoder(&notif);
  776. }
  777. if (index != playerIndex) pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]);
  778. }
  779. }
  780. //Ajoute json dans le tableau
  781. add_array_object(chain, &json);
  782. //Nettoyage
  783. clean_json_encoder(&json);
  784. }
  785. int spawn_object(Game* g, int x, int y, JsonEncoder* json) {
  786. int random, res = 0;
  787. //Generation random si spawn ou non
  788. srand(time(NULL));
  789. random = rand() % 100 + 1;
  790. if (random > SPAWNRATE) {
  791. return 0; //Pas de spawn
  792. }
  793. //Choisit l'objet
  794. random = rand() % 11;
  795. switch (random) {
  796. case OBJ_BCLASSIC:
  797. res = 1;
  798. add_string(json, "type", "classic");
  799. break;
  800. case OBJ_BMINE:
  801. res = 1;
  802. add_string(json, "type", "mine");
  803. break;
  804. case OBJ_BREMOTE:
  805. res = 1;
  806. add_string(json, "type", "remote");
  807. break;
  808. case OBJ_BOMBUP:
  809. res = 2;
  810. add_string(json, "type", "bomb_up");
  811. break;
  812. case OBJ_BOMBDOWN:
  813. res = 2;
  814. add_string(json, "type", "bomb_down");
  815. break;
  816. case OBJ_FIREPOWER:
  817. res = 2;
  818. add_string(json, "type", "fire_power");
  819. break;
  820. case OBJ_SCOOTER:
  821. res = 2;
  822. add_string(json, "type", "scooter");
  823. break;
  824. case OBJ_BROKENLEG:
  825. res = 2;
  826. add_string(json, "type", "broken_legs");
  827. break;
  828. case OBJ_LIFEUP:
  829. res = 2;
  830. add_string(json, "type", "life_up");
  831. break;
  832. case OBJ_LIFEMAX:
  833. res = 2;
  834. add_string(json, "type", "life_max");
  835. break;
  836. case OBJ_MAJOR:
  837. res = 2;
  838. add_string(json, "type", "major");
  839. break;
  840. }
  841. //Ajoute l'objet dans la partie
  842. object_add(g->object, random, x, y);
  843. //Ajoute postion au json
  844. char pos[20];
  845. memset(pos, 0, 20);
  846. snprintf(pos, 20, "%d,%d", x, y);
  847. add_string(json, "pos", pos);
  848. //Retourne type d'ajout
  849. return res;
  850. }
  851. void remove_player(Game* g, int playerIndex) {
  852. pthread_mutex_lock(&gameMutex[g->index]);
  853. pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]);
  854. g->nbPlayer--;
  855. delete_player(g->player[playerIndex]);
  856. pthread_mutex_unlock(&gameMutex[g->index]);
  857. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]);
  858. }
  859. void stop_game(Game* g) {
  860. pthread_mutex_lock(&gameMutex[g->index]);
  861. //Indique comme inactive
  862. g->active = false;
  863. //Suppr les joueurs
  864. for (int i = 0; i < MAXPLAYER; i++) {
  865. //pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + i]);
  866. if (g->player[i]->ini) {
  867. delete_player(g->player[i]);
  868. }
  869. free(g->player[i]);
  870. //pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]);
  871. }
  872. //Libere la memoire
  873. object_clean(g->object);
  874. free(g->object);
  875. for (int i = 0; i < g->width; i++) {
  876. free(g->map[i]);
  877. }
  878. free(g->map);
  879. free(g->mapName);
  880. free(g->mapContent);
  881. pthread_mutex_unlock(&gameMutex[g->index]);
  882. //Retire une game
  883. nbGame--;
  884. }
  885. void clean_games() {
  886. for (int i = 0; i < MAXGAME; i++) {
  887. if (game[i].active) {
  888. pthread_mutex_unlock(&gameMutex[i]);
  889. stop_game(&game[i]);
  890. }
  891. }
  892. }