game.c 39 KB

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