1 /*
2  * Programm XBLAST V1.2.14 or higher
3  * (C) by Oliver Vogel (e-mail: vogel@ikp.uni-koeln.de)
4  * May 9th 1996
5  * started August 1993
6  *
7  * Bot by Didier PLANTET (e-mail: plantet@info.enserb.u-bordeaux.fr)
8  * and Gr�goire ROBERT (e-mail : robert@info.enserb.u-bordeaux.fr)
9  * File: bot.c
10  * Bot IA ...
11  *
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public Licences as published
15  * by the Free Software Foundation; either version 2; or (at your option)
16  * any later version
17  *
18  * This program is distributed in the hope that it will entertaining,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILTY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
21  * Publis License for more details.
22  *
23  * You should have received a copy of the GNU General Public License along
24  * with this program; if not, write to the Free Software Foundation, Inc.
25  * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  */
27 
28 #include "xblast.h"
29 
30 #define _BOT_C
31 #define BOMB_STEP     2
32 #define NUM_FUSES 3
33 
34 #define PROB_POSER       10
35 #define PROB_SWAP       100
36 
37 #define BONUS_EXPLOSE    40
38 #define BONUS_TUE        60
39 #define BONUS_SIMPLE    100
40 #define BONUS_EXTRA     200
41 #define MALUS_MORT    -1000
42 
43 #define SLOW_SPEED       16
44 #define NORMAL_SPEED      8
45 #define FAST_SPEED        4
46 
47 typedef struct coord
48 {
49 	short x, y;
50 	short temps;
51 	short malus;
52 	struct coord *suivant;
53 } coord;
54 
55 static int fuse_times[NUM_FUSES] = { SHORT_FUSE, BOMB_TIME, LONG_FUSE };
56 
57 /* Tableau des bombes */
58 /*static Explosion *laby_bomb[MAZE_W][MAZE_H];*/
59 /* Liste des bombes */
60 static Explosion bombes_tmp[100];
61 /* Tableau des cases dangereuses : temps avant explosion */
62 static int laby_perf[MAZE_W][MAZE_H];
63 /* Nb de points dans chaque direction */
64 static int vote[NB_DIR];
65 /* Vaut VRAI si je pose */
66 static int vote_poser;
67 /* Vaut VRAI si je swappe */
68 static int vote_swap;
69 /* Vaut VRAI si j'effectue une action sp�ciale (appui sur +) */
70 static int vote_action_speciale;
71 /* Tableau des cases visit�es (bool�en) */
72 static int laby_visit[MAZE_W][MAZE_H];
73 /* Tableau des cases disparaissant */
74 static int laby_shrink[MAZE_W][MAZE_H];
75 
76 static int perf_max[NB_DIR];
77 static coord *file;
78 
79 static int gameTime;
80 
81 static BMPlayer *statut_joueurs;
82 /* Mon num�ro � moi */
83 static int num_bot;
84 static int nb_joueurs;
85 static int nb_ennemis_vivants;
86 static int temps_jeu;
87 /* La duree de deplacement entre 2 cases */
88 static int duree_deplacement;
89 
90 /* Score accord� au bonus du niveau */
91 static int bonus_extra;
92 
93 int dirige_vers_bonus (int x, int y, int dir);
94 										   /* Fouf lenteur -- *//* static int trace; */
95 
96 void
SetBotTime(int game_time)97 SetBotTime (int game_time)
98 {
99 	gameTime = game_time;
100 }
101 
102 coord *
creer_coord(int x,int y,int temps,int malus)103 creer_coord (int x, int y, int temps, int malus)
104 {
105 	coord *c = (coord *) malloc (sizeof (coord));
106 	c->x = x;
107 	c->y = y;
108 	c->temps = temps;
109 	c->malus = malus;
110 	c->suivant = NULL;
111 
112 	return c;
113 }
114 
115 void
enfiler(int x,int y,int temps,int malus)116 enfiler (int x, int y, int temps, int malus)
117 {
118 	coord *tmpc;
119 	coord *c = creer_coord (x, y, temps, malus);
120 
121 	if (file == NULL)
122 		file = c;
123 	else {
124 		tmpc = file;
125 		while (tmpc->suivant != NULL)
126 			tmpc = tmpc->suivant;
127 		tmpc->suivant = c;
128 	}
129 }
130 
131 coord *
defiler(void)132 defiler (void)
133 {
134 	coord *c = file;
135 
136 	file = file->suivant;
137 
138 	return c;
139 }
140 
141 /* Renvoie le nb de murs m'entourant */
142 int
test_murs(BMPlayer * ps)143 test_murs (BMPlayer * ps)
144 {
145 	int x = ps->x / BLOCK_WIDTH;
146 	int y = ps->y / BLOCK_HEIGHT + 1;
147 	int nb_murs = 0;
148 
149 	if (CheckMaze (x, y - 1)) {
150 		vote[UP] = MALUS_MORT;
151 		nb_murs++;
152 	}
153 	if (CheckMaze (x - 1, y)) {
154 		vote[LEFT] = MALUS_MORT;
155 		nb_murs++;
156 	}
157 	if (CheckMaze (x, y + 1)) {
158 		vote[DOWN] = MALUS_MORT;
159 		nb_murs++;
160 	}
161 	if (CheckMaze (x + 1, y)) {
162 		vote[RIGHT] = MALUS_MORT;
163 		nb_murs++;
164 	}
165 
166 	return nb_murs;
167 }
168 
169 /*Explosion *
170 foundBomb (int x, int y)
171 {
172   Explosion *p;
173 
174   for (p = expl_list; p != NULL; p = p->next)
175     if (p->x == x && p->y == y)
176       return p;
177 
178   return NULL;
179 }*/
180 
181 Explosion *
bombe_trouvee_tmp(int x,int y)182 bombe_trouvee_tmp (int x, int y)
183 {
184 	int i;
185 	for (i = 0; i < 100; i++)
186 		if (bombes_tmp[i].range != -1 && bombes_tmp[i].x == x && bombes_tmp[i].y == y)
187 			return &bombes_tmp[i];
188 
189 	return NULL;
190 }
191 
192 /*void
193 developpe_bombe (int range, int mazex, int mazey, int type)
194 {
195   Explosion *p;
196   int i,j;
197 
198   // right
199   for (i = 1; (i <= range) && CheckMazeOpen(mazex+i-1,mazey) ; i ++)
200     if (mazex+i < MAZE_W)
201       if (laby_perf[mazex][mazey] + i < laby_perf[mazex+i][mazey])
202 	{
203 	  laby_perf[mazex+i][mazey] = laby_perf[mazex][mazey] + i;
204 	  p = CheckBomb (mazex+i, mazey);
205 	  if (p != NULL && p->dir == GoStop)
206 	    developpe_bombe (p->range, mazex+i, mazey, BMTnormal);
207 	}
208 
209 	// Left
210   for (i = 1; (i <= range) && CheckMazeOpen(mazex-i+1,mazey) ; i ++)
211     if (mazex-i >= 0)
212       if (laby_perf[mazex][mazey] + i < laby_perf[mazex-i][mazey])
213 	{
214 	  laby_perf[mazex-i][mazey] = laby_perf[mazex][mazey] + i;
215 	  p = CheckBomb (mazex-i, mazey);
216 	  if (p != NULL && p->dir == GoStop)
217 	    developpe_bombe (p->range, mazex-i, mazey, BMTnormal);
218 	}
219 
220 	// Down
221   for (i = 1; (i <= range) && CheckMazeOpen(mazex,mazey+i-1) ; i ++)
222     if (mazey+i < MAZE_H)
223       if (laby_perf[mazex][mazey] + i < laby_perf[mazex][mazey+i])
224 	{
225 	  laby_perf[mazex][mazey+i] = laby_perf[mazex][mazey] + i;
226 	  p = CheckBomb (mazex, mazey+i);
227 	  if (p != NULL && p->dir == GoStop)
228 	    developpe_bombe (p->range, mazex, mazey+i, BMTnormal);
229 	}
230 
231 	// Up
232   for (i = 1; (i <= range) && CheckMazeOpen(mazex,mazey-i+1) ; i ++)
233     if (mazey-i >= 0)
234       if (laby_perf[mazex][mazey] + i < laby_perf[mazex][mazey-i])
235 	{
236 	  laby_perf[mazex][mazey-i] = laby_perf[mazex][mazey] + i;
237 	  p = CheckBomb (mazex, mazey-i);
238 	  if (p != NULL && p->dir == GoStop)
239 	    developpe_bombe (p->range, mazex, mazey-i, BMTnormal);
240 	}
241 
242 
243   if (type == BMTnapalm)
244     for (i= -2; i<=2; i++) {
245       if (mazex+i < MAZE_W && mazex+i >= 0)
246 	developpe_bombe (range/(ABS(i)+1), mazex+i, mazey, BMTnormal);
247       if (mazey+i < MAZE_H && mazey+i >= 0)
248 	developpe_bombe (range/(ABS(i)+1), mazex, mazey+i, BMTnormal);
249     }
250 
251   if (type == BMTgrenade)
252     if (range == 1) {
253       developpe_bombe(0, mazex-1, mazey-1, BMTblastnow);
254       developpe_bombe(0, mazex+1, mazey-1, BMTblastnow);
255       developpe_bombe(0, mazex-1, mazey+1, BMTblastnow);
256       developpe_bombe(0, mazex+1, mazey+1, BMTblastnow);
257     } else {
258       for (i = -((range)-1); i<=((range)-1); i++) {
259 	for (j = -((range)-1); j<=((range)-1); j++) {
260 	  developpe_bombe (1, mazex+i, mazey+j, BMTblastnow);
261 	}
262       }
263     }
264 }*/
265 
266 void
developpe_bombe_tmp(int range,int mazex,int mazey,int type,int count)267 developpe_bombe_tmp (int range, int mazex, int mazey, int type, int count)
268 {
269 	// Explosion *p;
270 	int i, j;
271 
272 	/* right */
273 	for (i = 1; (i <= range) && CheckMazeOpen (mazex + i - 1, mazey); i++)
274 		if (mazex + i < MAZE_W)
275 			if (laby_perf[mazex][mazey] + i < laby_perf[mazex + i][mazey])
276 				laby_perf[mazex + i][mazey] = laby_perf[mazex][mazey] + i * count;
277 
278 	/* Left */
279 	for (i = 1; (i <= range) && CheckMazeOpen (mazex - i + 1, mazey); i++)
280 		if (mazex - i >= 0)
281 			if (laby_perf[mazex][mazey] + i < laby_perf[mazex - i][mazey])
282 				laby_perf[mazex - i][mazey] = laby_perf[mazex][mazey] + i * count;
283 
284 	/* Down */
285 	for (i = 1; (i <= range) && CheckMazeOpen (mazex, mazey + i - 1); i++)
286 		if (mazey + i < MAZE_H)
287 			if (laby_perf[mazex][mazey] + i < laby_perf[mazex][mazey + i])
288 				laby_perf[mazex][mazey + i] = laby_perf[mazex][mazey] + i * count;
289 
290 	/* Up */
291 	for (i = 1; (i <= range) && CheckMazeOpen (mazex, mazey - i + 1); i++)
292 		if (mazey - i >= 0)
293 			if (laby_perf[mazex][mazey] + i < laby_perf[mazex][mazey - i])
294 				laby_perf[mazex][mazey - i] = laby_perf[mazex][mazey] + i * count;
295 
296 	if (type == BMTnapalm)
297 		for (i = -2; i <= 2; i++) {
298 			if (mazex + i < MAZE_W && mazex + i >= 0)
299 				developpe_bombe_tmp (range / (ABS (i) + 1), mazex + i, mazey, BMTnormal, count);
300 			if (mazey + i < MAZE_H && mazey + i >= 0)
301 				developpe_bombe_tmp (range / (ABS (i) + 1), mazex, mazey + i, BMTnormal, count);
302 		}
303 
304 	if (type == BMTgrenade) {
305 		if (range == 1) {
306 			developpe_bombe_tmp (0, mazex - 1, mazey - 1, BMTblastnow, count);
307 			developpe_bombe_tmp (0, mazex + 1, mazey - 1, BMTblastnow, count);
308 			developpe_bombe_tmp (0, mazex - 1, mazey + 1, BMTblastnow, count);
309 			developpe_bombe_tmp (0, mazex + 1, mazey + 1, BMTblastnow, count);
310 		}
311 		else {
312 			for (i = -((range) - 1); i <= ((range) - 1); i++) {
313 				for (j = -((range) - 1); j <= ((range) - 1); j++) {
314 					developpe_bombe_tmp (1, mazex + i, mazey + j, BMTblastnow, count);
315 				}
316 			}
317 		}
318 	}
319 }
320 
321 /* Traduit une direction en dx et dy */
322 void
conversion_direction(int dir,int * dx,int * dy)323 conversion_direction (int dir, int *dx, int *dy)
324 {
325 	*dx = 0;
326 	*dy = 0;
327 	switch (dir) {
328 	case UP:
329 		*dy = -1;
330 		break;
331 	case DOWN:
332 		*dy = 1;
333 		break;
334 	case LEFT:
335 		*dx = -1;
336 		break;
337 	case RIGHT:
338 		*dx = 1;
339 	}
340 }
341 
342 /* Les bonus extras sont-ils positifs ou n�gatifs ? */
343 void
def_score_extra(BMPlayer * ps)344 def_score_extra (BMPlayer * ps)
345 {
346 	bonus_extra = BONUS_EXTRA;
347 	/* La tortue */
348 	if (specialExtraFunc == SpecialExtraSlow) {
349 		if (!ps->iniextra_flags) {
350 			bonus_extra = -BONUS_SIMPLE / 2;
351 		}
352 		else {
353 			if (!ps->revextra_flags)
354 				bonus_extra = -BONUS_SIMPLE / 2;
355 			else
356 				bonus_extra = 0;	/* Si je suis d�j� lent, reprendre une tortue ne change rien */
357 		}
358 	}
359 	/* Le "bonus" invisible qui fait tourner */
360 	if (specialExtraFunc == SpecialExtraStunOthers) {
361 		bonus_extra = -2 * BONUS_SIMPLE;
362 	}
363 	/* La seringue */
364 	if (specialExtraFunc == SpecialExtraJunkie && ps->junkie == 0) {
365 		/* Si j'y ai d�j� touch�, j'ai int�r�t � en reprendre... */
366 		bonus_extra = -5 * BONUS_SIMPLE;
367 	}
368 	/* La mort imm�diate */
369 	if (specialExtraFunc == SpecialExtraPoison) {
370 		bonus_extra = -10 * BONUS_SIMPLE;
371 	}
372 
373 }
374 
375 /* Un bonus sur la case ? */
376 int
score_bonus(int x,int y)377 score_bonus (int x, int y)
378 {
379 	int bonus;
380 
381 	bonus = GetBlockExtra (x, y);
382 
383 	if (bonus == BTBomb || bonus == BTRange)
384 		bonus = BONUS_SIMPLE + 200;
385 	else if (bonus == BTSpecial || bonus == BTExtra) {
386 		if (specialExtraFunc != SpecialExtraPoison) {
387 			bonus = bonus_extra;
388 		}
389 		else {
390 			bonus = -BONUS_SIMPLE;
391 		}
392 
393 	}
394 	else						/* if (bonus == BTSwapper)
395 								   bonus = BONUS_EXTRA;
396 								   else */ if (bonus == BTEvil)
397 		bonus = -BONUS_SIMPLE;
398 
399 	else
400 		bonus = 0;
401 	return bonus;
402 }
403 
404 /* Est-il int�ressant de poser sur cette case ? */
405 int
score_explose(int x,int y,int portee_bombe)406 score_explose (int x, int y, int portee_bombe)
407 {
408 	int explose = 0;
409 	int dir, dx, dy;
410 	int i;
411 
412 	for (dir = 1; dir < NB_DIR; dir++) {
413 		conversion_direction (dir, &dx, &dy);
414 		i = 1;
415 		while (CheckMazeFree (x + i * dx, y + i * dy) && i <= portee_bombe)
416 			i++;
417 		/* Y a-t-il un mur � d�truire ? Et sinon, un bonus ? */
418 		if (GetBlockExtra (x + i * dx, y + i * dy) == BTExtra)
419 			explose += BONUS_EXPLOSE;
420 		else
421 			explose -= (score_bonus (x + i * dx, y + i * dy) / 4);
422 	}
423 	explose += 75;
424 	return explose;
425 }
426 
427 /* Est-ce que poser ici va menacer un autre joueur ? */
428 int
score_tue(int x,int y,int portee_bombe)429 score_tue (int x, int y, int portee_bombe)
430 {
431 	int tue = 0;
432 	int xmin = -1, xmax = -1, ymin = -1, ymax = -1;
433 	int j, jx, jy;
434 	int points;
435 	BMPlayer *ps;
436 
437 	/* Quelles cases puis-je atteindre ? */
438 	for (j = 1; j <= portee_bombe; j++) {
439 		if (xmin == -1 && (!CheckMazeFree (x - j, y) || j == portee_bombe))
440 			xmin = x - j;
441 		if (xmax == -1 && (!CheckMazeFree (x + j, y) || j == portee_bombe))
442 			xmax = x + j;
443 		if (ymin == -1 && (!CheckMazeFree (x, y - j) || j == portee_bombe))
444 			ymin = y - j;
445 		if (ymax == -1 && (!CheckMazeFree (x, y + j) || j == portee_bombe))
446 			ymax = y + j;
447 	}
448 	nb_ennemis_vivants = 0;
449 	for (j = 0; j < nb_joueurs; j++) {
450 		ps = statut_joueurs + j;
451 
452 		/* Le joueur n'est pas le bot et vit encore */
453 		if ((j != num_bot) && (ps->lives != 0)) {
454 			jx = ps->x / BLOCK_WIDTH;
455 			jy = ps->y / BLOCK_HEIGHT + 1;
456 
457 			points = BONUS_TUE;
458 
459 			/* Si le joueur est mon partenaire.... je vais �viter de le tuer ! */
460 			if (ps->team == (statut_joueurs + num_bot)->team)
461 				points = -points;
462 			else
463 				nb_ennemis_vivants++;
464 
465 			/* Je suis sur la m�me colonne */
466 			if ((x == jx) && ((ymin <= jy) && (jy <= ymax)))
467 				tue += points;
468 
469 			/* Je suis sur la m�me ligne (et pas sur la m�me colonne) */
470 			if ((y == jy) && (x != jx) && ((xmin <= jx) && (jx <= xmax)))
471 				tue += points;
472 
473 			/* Si le joueur a une mauvaise mort (poseuse, lenteur, mini, non-poseuse,
474 			   malfunction, teleport, ou *seringue*), je dois l'�viter */
475 			if ((x == jx) && (y == jy)) {
476 				if ((ps->illness == IllBomb) ||
477 					(ps->illness == IllSlow) ||
478 					(ps->illness == IllMini) ||
479 					(ps->illness == IllEmpty) ||
480 					(ps->illness == IllMalfunction) || (ps->illness == IllTeleport) || (ps->junkie))
481 					tue -= BONUS_SIMPLE;
482 			}
483 			/* sinon, j'essaie toujours de m'en approcher (s'il n'est pas mon partenaire) */
484 			else
485 				tue += points;
486 		}
487 	}
488 	return tue;
489 }
490 
491 /* Est-ce que je risque de me faire shrinker sur cette case ? */
492 int
score_shrink(int x,int y,int temps)493 score_shrink (int x, int y, int temps)
494 {
495 	int score = 0;
496 
497 	temps += temps_jeu;
498 	if (laby_shrink[x][y] - temps <= 16)
499 		score = MALUS_MORT;
500 	else if (laby_shrink[x][y] - temps <= 50)
501 		score = -BONUS_EXTRA;
502 	else if (laby_shrink[x][y] - temps <= 100)
503 		score = -BONUS_SIMPLE;
504 
505 	return score;
506 }
507 
508 /* Teste le danger et l'int�r�t d'une case... puis poursuit le parcours par niveau */
509 void
teste_case(coord * c,int dir_init,BMPlayer * ps)510 teste_case (coord * c, int dir_init, BMPlayer * ps)
511 {
512 	int perf = laby_perf[c->x][c->y] - c->temps;
513 	int portee_bombe = (ps->illness == IllMini) ? 1 : ps->range;
514 	int score, malus;
515 	int invincible = ps->invincible - c->temps;
516 	int tourne = ps->stunned - c->temps;
517 	int dir, dx, dy;
518 
519 	if (invincible > 0)
520 		perf += invincible;
521 	if (tourne < 0)
522 		tourne = 0;
523 
524 	/* Une bombe explosera sur le passage */
525 	if (perf <= 4)
526 		return;
527 
528 	/* La case dispara�tra */
529 	if (score_shrink (c->x, c->y, c->temps) == MALUS_MORT)
530 		return;
531 
532 	score = score_bonus (c->x, c->y);
533 	if (score <= -500)
534 		return;
535 
536 	/* Mise � jour du malus (score n�gatif le + faible du chemin) */
537 	malus = MIN (c->malus, score);
538 
539 	/* Calcul du score de la case */
540 	score += score_explose (c->x, c->y, portee_bombe);
541 	score += score_tue (c->x, c->y, portee_bombe);
542 	score += score_shrink (c->x, c->y, c->temps);
543 
544 	/* Mise � jour de la performance maximale de la direction dir_init */
545 	perf += score;
546 	if (perf > 10 * LONG_FUSE)
547 		perf += malus;
548 	perf_max[dir_init] = MAX (perf_max[dir_init], perf);
549 
550 	for (dir = 1; dir < NB_DIR; dir++) {
551 		conversion_direction (dir, &dx, &dy);
552 		/* Si je ne suis pas d�j� pass� par l�, s'il n'y a ni mur, ni bombe, je place la case dans la file */
553 		if (!laby_visit[c->x + dx][c->y + dy] && !CheckMaze (c->x + dx, c->y + dy)
554 			) {
555 			if (!ps->kick) {
556 				if (!CheckBomb (c->x + dx, c->y + dy)) {
557 					enfiler (c->x + dx, c->y + dy, c->temps + duree_deplacement + tourne, malus);
558 					laby_visit[c->x + dx][c->y + dy] = 1;
559 				}
560 
561 			}
562 			else {
563 				enfiler (c->x + dx, c->y + dy, c->temps + duree_deplacement + tourne, malus);
564 				laby_visit[c->x + dx][c->y + dy] = 1;
565 			}
566 		}
567 	}
568 }
569 
570 /* Remplissage du tableau laby_shrink (en d�but de niveau) */
571 void
init_laby_shrink()572 init_laby_shrink ()
573 {
574 	ShrinkGeneric *shrink_ptr = GetShrinkPtr ();
575 	XBScrambleData *scramble = GetScrDraw ();
576 	int temps;
577 	int x, y;
578 	unsigned mask;
579 
580 	for (x = 0; x < MAZE_W; x++)
581 		for (y = 0; y < MAZE_H; y++)
582 			laby_shrink[x][y] = 2 * GAME_TIME;
583 
584 	/* La liste point�e par shrink_ptr se termine par une cellule (2 * GAME_TIME, 0, 0) */
585 	while (shrink_ptr->time < 2 * GAME_TIME) {
586 		temps = shrink_ptr->time;
587 		x = shrink_ptr->x;
588 		y = shrink_ptr->y;
589 		if (laby_shrink[x][y] > temps)
590 			laby_shrink[x][y] = temps;
591 		shrink_ptr++;
592 	}
593 
594 	/* Blocs surgissant sur le plateau */
595 	temps = scramble->time - 4;
596 	for (y = 0; y < MAZE_H; y++) {
597 		if (0 != scramble->row[y]) {
598 			for (x = 0, mask = 1; x < MAZE_W; x++, mask <<= 1) {
599 				if (mask & scramble->row[y]) {
600 					if (laby_shrink[x][y] > temps)
601 						laby_shrink[x][y] = temps;
602 				}
603 			}
604 		}
605 	}
606 
607 /*  for (y = 0; y < MAZE_H; y++) {
608       for (x = 0; x < MAZE_W; x++)
609 	fprintf (stderr, "%d ", laby_shrink[x][y]);
610       fprintf (stderr, "\n");
611     }*/
612 }
613 
614 /* Aucune case n'a �t� visit�e (d�but d'un parcours par niveau) */
615 void
init_laby_visit(int x,int y)616 init_laby_visit (int x, int y)
617 {
618 	int mazex, mazey;
619 
620 	for (mazex = 0; mazex < MAZE_W; mazex++)
621 		for (mazey = 0; mazey < MAZE_H; mazey++)
622 			laby_visit[mazex][mazey] = 0;
623 
624 /*  memset (&laby_visit, 0, MAZE_W * MAZE_H * sizeof (int));*/
625 
626 	laby_visit[x][y] = 1;
627 }
628 
629 static BMDirection turn_clockwise[MAX_DIR] = {
630 	GoStop, GoRight, GoUp, GoLeft, GoDown, GoDefault
631 };
632 
633 static BMDirection turn_anticlockwise[MAX_DIR] = {
634 	GoStop, GoLeft, GoDown, GoRight, GoUp, GoDefault
635 };
636 
637 static BMDirection turn_opposite[MAX_DIR] = {
638 	GoStop, GoDown, GoRight, GoUp, GoLeft, GoDefault
639 };
640 
641 void
calc_laby_perf()642 calc_laby_perf ()
643 {
644 	int player;
645 	int i, j, k;
646 	int dx, dy;
647 	int temps;
648 	Explosion *p;
649 	Explosion *p2;
650 
651 	/* On traite d'abord les bombes en train d'exploser (count > 0) */
652 	for (i = 0; i < 100; i++) {
653 		p = &bombes_tmp[i];
654 
655 		if (p->range == -1)
656 			continue;
657 
658 		if (p->count < 0)
659 			continue;
660 
661 		if (laby_perf[p->x][p->y] > -p->count) {
662 			laby_perf[p->x][p->y] = -p->count;
663 			developpe_bombe_tmp (p->range, p->x, p->y, p->type, -p->count);
664 		}
665 		else
666 			developpe_bombe_tmp (p->range, p->x, p->y, BMTnormal, -p->count);
667 
668 		p->range = -1;
669 	}
670 
671 	for (temps = 0; temps < LONG_FUSE; temps++) {	/* On deplace case par case */
672 		for (i = 0; i < 100; i++) {	/* Pour chaque bombe */
673 			p = &bombes_tmp[i];
674 
675 			if (p->range == -1)
676 				continue;
677 
678 			if (temps == -p->count || laby_perf[p->x][p->y] <= temps) {	/* On explose la */
679 				if (laby_perf[p->x][p->y] > -p->count) {
680 					laby_perf[p->x][p->y] = -p->count;
681 					developpe_bombe_tmp (p->range, p->x, p->y, p->type, -p->count);
682 				}
683 				else
684 					developpe_bombe_tmp (p->range, p->x, p->y, BMTnormal, -p->count);
685 
686 				p->range = -1;
687 				continue;
688 			}
689 
690 			if (p->dir == GoStop) {
691 				continue;
692 			}
693 			conversion_direction (p->dir, &dx, &dy);
694 			/* Si on cogne une bombe */
695 			if (p->dx * dx >= 0 && p->dy * dy >= 0 && bombe_trouvee_tmp (p->x + dx, p->y + dy)) {
696 				if (doBombClick == BombClickNone) {
697 					p->dir = GoStop;
698 					p->dx = 0;
699 					p->dy = 0;
700 				}
701 				else if (doBombClick == BombClickInitial) {
702 					p->dir = initialBombDir;
703 					conversion_direction (p->dir, (int *)&p->dx, (int *)&p->dy);
704 				}
705 				else if (doBombClick == BombClickThru) {
706 				}
707 				else if (doBombClick == BombClickSnooker) {
708 					p2 = bombe_trouvee_tmp (p->x + dx, p->y + dy);
709 					p2->dir = p->dir;
710 					/* On met a 0 l'offset de l'autre direction */
711 					p2->dx = p2->dx * ABS (dx);
712 					p2->dy = p2->dy * ABS (dy);
713 					/* La bombe qui cogne arrete de bouger */
714 					p->dir = GoStop;
715 					p->dx = 0;
716 					p->dy = 0;
717 				}
718 				else if (doBombClick == BombClickContact) {
719 					p->dir = GoStop;
720 					p->dx = 0;
721 					p->dy = 0;
722 					if (laby_perf[p->x][p->y] > -p->count)
723 						laby_perf[p->x][p->y] = -p->count;
724 					developpe_bombe_tmp (p->range, p->x, p->y, p->type, -p->count);
725 					bombes_tmp[i].range = -1;
726 				}
727 				else if (doBombClick == BombClickContact) {
728 					p->dir = turn_clockwise[p->dir];
729 					p->dx = 0;
730 					p->dy = 0;
731 				}
732 				else if (doBombClick == BombClickAnticlockwise) {
733 					p->dir = turn_anticlockwise[p->dir];
734 					p->dx = 0;
735 					p->dy = 0;
736 				}
737 				else if (doBombClick == BombClickRandomdir) {
738 					p->dir = (int)(((float)rand () / (RAND_MAX + 1.0)) * (4)) + 1;
739 					p->dx = 0;
740 					p->dy = 0;
741 				}
742 				else if (doBombClick == BombClickRebound) {
743 					p->dir = turn_opposite[p->dir];
744 				}
745 			}
746 			/* Ou un mur */
747 			else if (p->dx == 0 && p->dy == 0 && !CheckMazeFree (p->x + dx, p->y + dy)) {
748 				if (doWallClick == BombClickNone) {
749 					p->dir = GoStop;
750 					p->dx = 0;
751 					p->dy = 0;
752 				}
753 				else if (doWallClick == BombClickInitial) {
754 					p->dir = initialBombDir;
755 					conversion_direction (p->dir, (int *)&p->dx, (int *)&p->dy);
756 				}
757 				else if (doWallClick == BombClickThru) {
758 				}
759 				else if (doWallClick == BombClickContact) {
760 					p->dir = GoStop;
761 					p->dx = 0;
762 					p->dy = 0;
763 					if (laby_perf[p->x][p->y] > -p->count)
764 						laby_perf[p->x][p->y] = -p->count;
765 					developpe_bombe_tmp (p->range, p->x, p->y, p->type, -p->count);
766 					bombes_tmp[i].range = -1;
767 				}
768 				else if (doWallClick == BombClickContact) {
769 					p->dir = turn_clockwise[p->dir];
770 					p->dx = 0;
771 					p->dy = 0;
772 				}
773 				else if (doWallClick == BombClickAnticlockwise) {
774 					p->dir = turn_anticlockwise[p->dir];
775 					p->dx = 0;
776 					p->dy = 0;
777 				}
778 				else if (doWallClick == BombClickRandomdir) {
779 					p->dir = (BMDirection) (int)((float)rand () / (RAND_MAX + 1.0)) * MAX_DIR;
780 					p->dx = 0;
781 					p->dy = 0;
782 				}
783 				else if (doWallClick == BombClickRebound) {
784 					p->dir = turn_opposite[p->dir];
785 				}
786 			}
787 			/* Un joueur */
788 			else {
789 
790 				for (player = 0; player < nb_joueurs; player++) {
791 					if ((statut_joueurs[player].invincible == 0)
792 						&& (ABS (p->x * BLOCK_WIDTH + p->dx - statut_joueurs[player].x)
793 							< BOMB_STUN_X)
794 						&& (ABS (p->y * BLOCK_HEIGHT + p->dy
795 								 - statut_joueurs[player].y - BLOCK_HEIGHT) < BOMB_STUN_Y))
796 						break;
797 				}
798 
799 				if (player < nb_joueurs) {
800 					if (doPlayerClick == BombClickNone) {
801 						p->dir = GoStop;
802 						p->dx = 0;
803 						p->dy = 0;
804 					}
805 					else if (doPlayerClick == BombClickInitial) {
806 						p->dir = initialBombDir;
807 						conversion_direction (p->dir, (int *)&p->dx, (int *)&p->dy);
808 					}
809 					else if (doPlayerClick == BombClickThru) {
810 					}
811 					else if (doPlayerClick == BombClickContact) {
812 						p->dir = GoStop;
813 						p->dx = 0;
814 						p->dy = 0;
815 						if (laby_perf[p->x][p->y] > -p->count)
816 							laby_perf[p->x][p->y] = -p->count;
817 						developpe_bombe_tmp (p->range, p->x, p->y, p->type, -p->count);
818 						bombes_tmp[i].range = -1;
819 					}
820 					else if (doPlayerClick == BombClickContact) {
821 						p->dir = turn_clockwise[p->dir];
822 						p->dx = 0;
823 						p->dy = 0;
824 					}
825 					else if (doPlayerClick == BombClickAnticlockwise) {
826 						p->dir = turn_anticlockwise[p->dir];
827 						p->dx = 0;
828 						p->dy = 0;
829 					}
830 					else if (doPlayerClick == BombClickRandomdir) {
831 						p->dir = (int)(((float)rand () / (RAND_MAX + 1.0)) * (4)) + 1;
832 						p->dx = 0;
833 						p->dy = 0;
834 					}
835 					else if (doPlayerClick == BombClickRebound) {
836 						p->dir = turn_opposite[p->dir];
837 					}
838 
839 				}
840 			}
841 
842 			conversion_direction (p->dir, &dx, &dy);
843 
844 			p->dy += dy * BOMB_VY;
845 			p->dx += dx * BOMB_VX;
846 
847 			if (p->dx * dx >= BLOCK_WIDTH / 2) {
848 				p->dx -= dx * BLOCK_WIDTH;
849 				p->x += dx;
850 			}
851 
852 			if (p->dy * dy >= BLOCK_HEIGHT / 2) {
853 				p->dy -= dy * BLOCK_HEIGHT;
854 				p->y += dy;
855 			}
856 			if (p->x < 0)
857 				p->x = 0;
858 			if (p->y < 0)
859 				p->y = 0;
860 
861 			/* On aime pas tres bien etre sur la trajectoire d'une bombe */
862 			laby_perf[p->x][p->y] = MIN (laby_perf[p->x][p->y], 50 * LONG_FUSE - 500 + temps * 4);
863 
864 		}
865 
866 		for (i = 0; i < 100; i++) {	/* Pour chaque bombe */
867 			p = &bombes_tmp[i];
868 
869 			if (p->range == -1)
870 				continue;
871 
872 			/* Les bombes en train d'exploser ne se repoduisent pas ... */
873 			if (p->count <= 0)
874 				continue;
875 
876 			if (p->type == BMTfungus) {	/* On developpe les bombes fungus ... */
877 				if (p->count == (fuse_times[curBombTime] * 3 / 5)) {
878 
879 					for (j = -1; j <= 1; j++) {
880 						if ((p->x + j < MAZE_W) && (p->x + j > -1)
881 							&& !CheckMazeSolid (p->x + j, p->y)) {
882 							/* On trouve un emplacement libre ... */
883 							for (k = 0; k < 100; k++)
884 								if (bombes_tmp[k].range == -1)
885 									break;
886 							bombes_tmp[k].x = p->x + j;
887 							bombes_tmp[k].y = p->y;
888 							bombes_tmp[k].range = p->range;
889 							bombes_tmp[k].type = BMTfungus;
890 							bombes_tmp[k].dir = GoStop;
891 							bombes_tmp[k].count = fuse_times[curBombTime];
892 						}
893 
894 						if ((p->y + j < MAZE_H) && (p->y + j > -1)
895 							&& !CheckMazeSolid (p->x, p->y + j)) {
896 							/* On trouve un emplacement libre ... */
897 							for (k = 0; k < 100; k++)
898 								if (bombes_tmp[k].range == -1)
899 									break;
900 							bombes_tmp[k].x = p->x;
901 							bombes_tmp[k].y = p->y + j;
902 							bombes_tmp[k].range = p->range;
903 							bombes_tmp[k].type = BMTfungus;
904 							bombes_tmp[k].dir = GoStop;
905 							bombes_tmp[k].count = fuse_times[curBombTime];
906 						}
907 					}
908 				}
909 			}
910 		}
911 	}
912 }
913 
914 void
init_laby_perf()915 init_laby_perf ()
916 {
917 	int i;
918 	int mazex, mazey;
919 	Explosion *p;
920 
921 	for (mazex = 0; mazex < MAZE_W; mazex++)
922 		for (mazey = 0; mazey < MAZE_H; mazey++)
923 			laby_perf[mazex][mazey] = 50 * LONG_FUSE;
924 
925 	for (i = 0; i < 100; i++)
926 		bombes_tmp[i].range = -1;
927 
928 	for (p = exploList, i = 1; p != NULL; p = p->next, i++)
929 		bombes_tmp[i] = *p;
930 
931 	calc_laby_perf ();
932 }
933 
934 void
init_laby_perf_pose(int x,int y,int range,int count,int type)935 init_laby_perf_pose (int x, int y, int range, int count, int type)
936 {
937 	int i;
938 	int mazex, mazey;
939 	Explosion *p;
940 
941 	for (mazex = 0; mazex < MAZE_W; mazex++)
942 		for (mazey = 0; mazey < MAZE_H; mazey++)
943 			laby_perf[mazex][mazey] = 50 * LONG_FUSE;
944 
945 	for (i = 0; i < 100; i++)
946 		bombes_tmp[i].range = -1;
947 
948 	for (p = exploList, i = 1; p != NULL; p = p->next, i++)
949 		bombes_tmp[i] = *p;
950 
951 	bombes_tmp[i].x = x;
952 	bombes_tmp[i].y = y;
953 	bombes_tmp[i].range = range;
954 	bombes_tmp[i].count = -count;
955 	bombes_tmp[i].type = type;
956 
957 	calc_laby_perf ();
958 
959 }
960 
961 void
init_laby_perf_biscotte()962 init_laby_perf_biscotte ()
963 {
964 	int i;
965 	int mazex, mazey;
966 	Explosion *p;
967 
968 	for (mazex = 0; mazex < MAZE_W; mazex++)
969 		for (mazey = 0; mazey < MAZE_H; mazey++)
970 			laby_perf[mazex][mazey] = 50 * LONG_FUSE;
971 
972 	for (i = 0; i < 100; i++)
973 		bombes_tmp[i].range = -1;
974 
975 	for (p = exploList, i = 1; p != NULL; p = p->next, i++) {
976 		bombes_tmp[i] = *p;
977 		if (p->player)
978 			if (p->player->id == num_bot)
979 				bombes_tmp[i].count = 0;
980 	}
981 
982 	calc_laby_perf ();
983 }
984 
985 void
parcours_par_niveau(BMPlayer * ps)986 parcours_par_niveau (BMPlayer * ps)
987 {
988 	coord *c;
989 	int dir;
990 	int x = ps->x / BLOCK_WIDTH;
991 	int y = ps->y / BLOCK_HEIGHT + 1;
992 	int dx, dy;
993 	int malus;
994 	int portee_bombe = (ps->illness == IllMini) ? 1 : ps->range;
995 
996 	/* for (dir = 0; dir < NB_DIR; dir++)
997 	   perf_max[dir] = 0;
998 	 */
999 	perf_max[STOP] = score_shrink (x, y, ps->stunned);
1000 	/* Ajout de la s�curit� et de l'invincibilit� du joueur si la case ne se fait pas shrinker imm�diatement */
1001 	if (perf_max[STOP] > MALUS_MORT)
1002 		perf_max[STOP] += laby_perf[x][y] + ps->invincible;
1003 
1004 	/* Ajout des bonus explose et tue si la case est s�re */
1005 	if (perf_max[STOP] == 50 * LONG_FUSE) {
1006 		perf_max[STOP] += score_explose (x, y, portee_bombe);
1007 		perf_max[STOP] += score_tue (x, y, portee_bombe);
1008 	}
1009 	perf_max[STOP] += 60;
1010 
1011 	for (dir = 1; dir < NB_DIR; dir++) {
1012 		conversion_direction (dir, &dx, &dy);
1013 		init_laby_visit (x, y);
1014 		/* Eviter mur et shrink imm�diat */
1015 		if (!CheckMaze (x + dx, y + dy) && score_shrink (x + dx, y + dy, ps->stunned) > MALUS_MORT
1016 			&& (dirige_vers_bonus (x, y, dir) != -1))
1017 			if (!CheckBomb (x + dx, y + dy)) {
1018 				malus = MIN (0, score_bonus (x + dx, y + dy));
1019 				enfiler (x + dx, y + dy, duree_deplacement + ps->stunned, malus);
1020 				while (file) {
1021 					c = defiler ();
1022 					teste_case (c, dir, ps);
1023 					free (c);
1024 				}
1025 			}
1026 	}
1027 }
1028 
1029 /* Renvoie VRAI s'il est possible et int�ressant de poser une bombe */
1030 int
souhaite_poser_bombe(BMPlayer * ps)1031 souhaite_poser_bombe (BMPlayer * ps)
1032 {
1033 	int score;
1034 	int mazex, mazey;
1035 	int portee_bombe = (ps->illness == IllMini) ? 1 : ps->range;
1036 	// int j;
1037 
1038 	mazex = ps->x / BLOCK_WIDTH;
1039 	mazey = ps->y / BLOCK_HEIGHT + 1;
1040 
1041 	/* Est-il possible de poser ? */
1042 
1043 	/* Pas de bombe sur la case */
1044 	if (CheckBomb (mazex, mazey))
1045 		return XBFalse;
1046 
1047 	/* Je n'ai ni la non poseuse, ni la t�l�porte, ni la mal-function */
1048 	if (ps->illness == IllEmpty || ps->illness == IllTeleport || ps->illness == IllMalfunction)
1049 		return XBFalse;
1050 
1051 	/* Il me reste des bombes... */
1052 	if (ps->bombs == 0)
1053 		return XBFalse;
1054 
1055 	/* Est-il int�ressant de poser ? */
1056 	score = score_explose (mazex, mazey, portee_bombe) + score_tue (mazex, mazey, portee_bombe);
1057 
1058 	//  fprintf(stderr," socre expl %i \n",score);
1059 	if (score < 0)
1060 		return XBFalse;
1061 
1062 	/* Aucune raison particuli�re de poser... au hasard pr�s */
1063 	if (score == 0 && (int)(((float)rand () / (RAND_MAX + 1.0)) * (PROB_POSER)) != 0)
1064 		return XBFalse;
1065 
1066 	/* S'il reste au moins un autre joueur vivant, j'essaie de poser */
1067 	return (nb_ennemis_vivants > 0);
1068 }
1069 
1070 /* Renvoie VRAI si je me dirige vers un bonus */
1071 int
dirige_vers_bonus(int x,int y,int dir)1072 dirige_vers_bonus (int x, int y, int dir)
1073 {
1074 	int dx, dy;
1075 
1076 	conversion_direction (dir, &dx, &dy);
1077 	if ((CheckBonuses2 (x + dx, y + dy)) && (specialExtraFunc == SpecialExtraPoison)) {	//fprintf(stderr," field  poisoned\n");
1078 		return -1;				// POISON!!!
1079 	}
1080 	else {
1081 
1082 		return CheckBonuses (x + dx, y + dy);
1083 	}
1084 
1085 }
1086 
1087 /* Choix de la meilleure direction */
1088 static void
choix_direction(int * choix_dir,int * max_perf)1089 choix_direction (int *choix_dir, int *max_perf)
1090 {
1091 	int dir = 0, dir1 = 0;
1092 	static int old_dir = 0;
1093 	*choix_dir = STOP;
1094 	*max_perf = 0;
1095 	for (dir = 0; dir < NB_DIR; dir++) {
1096 		/* Ajout d'un petit bonus al�atoire si la case est s�re */
1097 		if (perf_max[dir] > 10 * LONG_FUSE)
1098 			perf_max[dir] += (int)(((float)rand () / (RAND_MAX + 1.0)) * (10));	//
1099 		//  GameRandomNumber1 (10);
1100 
1101 		/* Je choisis la destination ayant la meilleure performance */
1102 		// if(dir==old_dir && dir!=0) perf_max[dir]+=50;
1103 		if (dir == old_dir && dir == 0)
1104 			perf_max[dir] -= 100;
1105 		if (perf_max[dir] > *max_perf) {
1106 			*max_perf = perf_max[dir];
1107 			*choix_dir = dir;
1108 		}
1109 		else if ((perf_max[dir] == *max_perf) &&
1110 				 ((int)((float)rand () / (RAND_MAX + 1.0)) * (5) == dir))
1111 			*choix_dir = dir;
1112 	}
1113 	for (dir = 0; dir < NB_DIR; dir++) {
1114 
1115 		for (dir1 = 0; dir1 < NB_DIR; dir1++) {
1116 			if (perf_max[dir] == perf_max[dir1] && dir != dir1) {
1117 				if (dir < dir1) {
1118 					if (dir == old_dir)
1119 						perf_max[dir] += 75;
1120 					else
1121 						perf_max[dir]++;
1122 
1123 				}
1124 			}
1125 		}
1126 	}
1127 	for (dir = 0; dir < NB_DIR; dir++) {
1128 		//    fprintf(stderr,"dir %i prfmax %i olddir %i\n",dir, perf_max[dir],old_dir);
1129 		if (perf_max[dir] > *max_perf) {
1130 			*max_perf = perf_max[dir];
1131 			*choix_dir = dir;
1132 		}
1133 
1134 	}
1135 	for (dir = 0; dir < NB_DIR; dir++) {
1136 		perf_max[dir] = 0;
1137 	}
1138 	old_dir = *choix_dir;
1139 }
1140 
1141 /* Renvoie VRAI si je d�cide d'utiliser la t�l�commande MAINTENANT */
1142 int
test_biscotte(BMPlayer * ps)1143 test_biscotte (BMPlayer * ps)
1144 {
1145 	int declenche = XBFalse;
1146 	int mes_bombes = 0;
1147 	int securite_init;
1148 	Explosion *bombe;
1149 	int x, y;
1150 
1151 	x = ps->x / BLOCK_WIDTH;
1152 	y = ps->y / BLOCK_HEIGHT + 1;
1153 	securite_init = laby_perf[x][y];
1154 
1155 	/* Parcours de toutes les bombes du plateau */
1156 	for (bombe = exploList; bombe != NULL; bombe = bombe->next)
1157 		/* Si cette bombe m'appartient... */
1158 		if (bombe->player == ps) {
1159 			mes_bombes++;
1160 			/* ... je la fais exploser ! */
1161 			/*      laby_perf[bombe->x][bombe->y] = 0;
1162 			   developpe_bombe (bombe->range, bombe->x, bombe->y, bombe->type); */
1163 			init_laby_perf_biscotte ();
1164 		}
1165 	if ((mes_bombes > 0) && ((laby_perf[x][y] == securite_init) || (ps->invincible > 5)))
1166 		declenche = XBTrue;
1167 
1168 	return declenche;
1169 }
1170 
1171 /* Renvoie VRAI si j'ai envie de swapper MAINTENANT.*/
1172 int
test_swap(BMPlayer * ps,int perf)1173 test_swap (BMPlayer * ps, int perf)
1174 {
1175 	int vote_swap = XBFalse;
1176 	int partenaire;
1177 	int equipe_complete = XBFalse;
1178 	int joueur;
1179 
1180 	/* Swap al�atoire si j'ai au moins 2 swaps */
1181 	/*  if (ps->swapposition > 1)
1182 	   vote_swap = (GameRandomNumber1 (PROB_SWAP) == 0); */
1183 
1184 	/* Si nous jouons par �quipe */
1185 	if (statut_joueurs->team == (statut_joueurs + 1)->team) {
1186 		partenaire = ((num_bot) / 2) * 2 + 1 - (num_bot % 2);
1187 		/* Si mon partenaire est mort */
1188 		if ((statut_joueurs + partenaire)->lives == 0) {
1189 			for (joueur = 0; joueur < nb_joueurs; joueur += 2)
1190 				/* Si les deux joueurs d'une autre �quipe sont encore vivants. */
1191 				if (((statut_joueurs + joueur)->team != ps->team)
1192 					&& ((statut_joueurs + joueur)->lives > 0)
1193 					&& ((statut_joueurs + joueur + 1)->lives > 0))
1194 					equipe_complete = XBTrue;
1195 			/* S'il n'y a pas d'�quipe compl�te... je swappe ! */
1196 			if (!equipe_complete)
1197 				vote_swap = XBTrue;
1198 		}
1199 	}
1200 	/* Je swappe si je suis coinc� entre 4 murs (et que l'on ne joue pas par �quipe) */
1201 	else if (ps->teleport == 0 && test_murs (ps) == 4)
1202 		vote_swap = XBTrue;
1203 
1204 	/* Je swappe si je vais mourir */
1205 	if (ps->dying || perf <= duree_deplacement)
1206 		vote_swap = XBTrue;
1207 
1208 	return vote_swap;
1209 }
1210 
1211 void
actions(BMPlayer * ps)1212 actions (BMPlayer * ps)
1213 {
1214 	int i;
1215 	int dx = 0, dy = 0;
1216 	static int olddx = 0, olddy = 0;
1217 	int dir;
1218 	int max_perf;
1219 	int choix_dir, prec_choix_dir;
1220 	int x, y;
1221 	int duree_meche, portee_bombe, type_bombe;
1222 
1223 	x = ps->x / BLOCK_WIDTH;
1224 	y = ps->y / BLOCK_HEIGHT + 1;
1225 	portee_bombe = (ps->illness == IllMini) ? 1 : ps->range;
1226 	type_bombe = BMTdefault;
1227 	def_score_extra (ps);
1228 
1229 	/* Remplissage du tableau my_maze */
1230 	init_laby_perf ();
1231 
1232 	/* Je cherche les cases les plus s�res, en partant dans toutes les directions */
1233 	parcours_par_niveau (ps);
1234 
1235 	/* Choix de la meilleure direction */
1236 	choix_direction (&choix_dir, &max_perf);
1237 	prec_choix_dir = choix_dir;
1238 
1239 	/* Et si j'essayais de poser une tit' bombe ? */
1240 	vote_poser = XBFalse;
1241 	if (souhaite_poser_bombe (ps)) {
1242 		/* Calcul de la dur�e de m�che */
1243 		duree_meche = fuse_times[curBombTime];
1244 		/* Calcul des effets de l'explosion de cette bombe */
1245 		/*    if (laby_perf[x][y] > duree_meche)
1246 		   laby_perf[x][y] = duree_meche;
1247 		   developpe_bombe (portee_bombe, x, y, type_bombe); */
1248 		//  init_laby_perf_pose (x, y, portee_bombe, duree_meche, type_bombe);
1249 
1250 		/* Je cherche les cases les plus s�res, en partant dans toutes les directions */
1251 		parcours_par_niveau (ps);
1252 		/* Est-ce que poser me laisse la vie sauve ? */
1253 		for (dir = 0; dir < NB_DIR; dir++) {
1254 			if (perf_max[dir] > 10 * LONG_FUSE || duree_meche < ps->invincible) {
1255 				vote_poser = XBTrue;
1256 				break;
1257 			}
1258 			//      fprintf(stderr," perf_max %i ",perf_max[dir]);
1259 
1260 		}
1261 		//    fprintf(stderr," dest %i \n",10 * LONG_FUSE);
1262 		/* Si oui, je pose... et choisis la direction de d�part */
1263 		if (vote_poser) {
1264 			choix_direction (&choix_dir, &max_perf);
1265 			/* Je ne pose pas si j'ai d�cid� d'aller vers un bonus (risque de mourir) */
1266 			/* Remarque : m�thode provisoire � am�liorer... */
1267 			if (dirige_vers_bonus (x, y, choix_dir)) {
1268 				//  fprintf(stderr, " go for bonus!\n");
1269 
1270 				vote_poser = XBFalse;
1271 				//  choix_dir = prec_choix_dir;
1272 			}
1273 			/*je ne pose pas si il ny a place pour ca (Skywalker) */
1274 			if (!(ps->remote_control > 0)) {
1275 				i = 1;
1276 				dx = 1;
1277 				conversion_direction (choix_dir, &dx, &dy);
1278 				if (!CheckBomb (x - olddx, y - olddy))
1279 					i = 0;
1280 				/* pas verifier si ma position est libre */
1281 
1282 				if (dx - 1 != 0 && dy != 0)
1283 					if (		//CheckBomb (x-olddx, y-olddy)&&
1284 						   CheckMazeFree2 (x + dx - 1, y + dy) && !CheckBomb (x + dx - 1, y + dy)) {
1285 						i = 0;
1286 					}
1287 
1288 				if (dx != 0 && dy + 1 != 0)
1289 					if (		//CheckBomb (x-olddx, y-olddy)&&
1290 						   CheckMazeFree2 (x + dx, y + dy + 1) && !CheckBomb (x + dx, y + dy + 1)) {
1291 						i = 0;
1292 					}
1293 				if (dx != 0 && dy - 1 != 0)
1294 					if (		//CheckBomb (x-olddx, y-olddy)&&
1295 						   CheckMazeFree2 (x + dx, y + dy - 1) && !CheckBomb (x + dx, y + dy - 1)) {
1296 						i = 0;
1297 					}
1298 				if (dx + 1 != 0 && dy != 0)
1299 					/* verifier si il y a place pour escape de la bomb posee */
1300 					if (		//CheckBomb (x-olddx, y-olddy)&&
1301 						   CheckMazeFree2 (x + dx + 1, y + dy) && !CheckBomb (x + dx + 1, y + dy)) {
1302 						i = 0;
1303 					}
1304 
1305 				if (i) {
1306 					vote_poser = XBFalse;
1307 				}
1308 				if (olddx == -dx && olddy == -dy) {
1309 					vote_poser = XBFalse;
1310 				}
1311 				if (ps->invincible > 5 && ps->remote_control > 0) {
1312 					vote_poser = XBTrue;
1313 				}
1314 			}
1315 			//  if(
1316 		}
1317 	}
1318 
1319 	/* Si je vais mourir, j'essaie de toute fa�on de poser et de changer de case. */
1320 	if (max_perf <= 30) {
1321 		vote[STOP] -= 300;
1322 		vote_poser = XBTrue;
1323 	}
1324 
1325 	/* Est-ce que j'effectue une action sp�ciale ? */
1326 	vote_action_speciale = XBFalse;
1327 
1328 	/* Si j'ai la t�l�commande (biscotte pour les intimes) */
1329 	if (ps->remote_control > 0 && (max_perf > 10 * LONG_FUSE || ps->invincible > 5))
1330 		if (test_biscotte (ps)) {
1331 			vote_action_speciale = XBTrue;
1332 			choix_dir = STOP;
1333 			vote_poser = XBFalse;
1334 		}
1335 	/* Si je peux morpher, je morphe */
1336 	if (ps->num_morph > 0) {
1337 		vote_action_speciale = XBTrue;
1338 	}
1339 	/* Si je peux me t�l�porter et que je risque de mourir */
1340 	if (ps->teleport > 0 && max_perf < 50) {
1341 		vote_action_speciale = XBTrue;
1342 		choix_dir = STOP;
1343 		vote_poser = XBFalse;
1344 	}
1345 
1346 	/* Si j'ai des bombes sp�ciales */
1347 	if (ps->special_bombs > 0) {
1348 		/* Si ce sont des bombes explosant imm�diatement
1349 		   if (get_current_level ()->bomb.buttonBMT == BMTblastnow)
1350 		   algo simpliste � modifier
1351 		   if (vote_poser && ps->invincible > 5)
1352 		   {
1353 		   vote_action_speciale = XBTrue;
1354 		   vote_poser = XBFalse;
1355 		   } */
1356 	}
1357 	/* Ai-je envie de swapper ? */
1358 	vote_swap = XBFalse;
1359 	/* if (ps->swapper > 0 && test_swap (ps, max_perf))
1360 	   vote_swap = XBTrue; */
1361 
1362 	vote[choix_dir] += 200;
1363 	olddy = dy;
1364 	olddx = dx;
1365 }
1366 
1367 /* Inversion des directions */
1368 int
inversion(int dir)1369 inversion (int dir)
1370 {
1371 	switch (dir) {
1372 	case UP:
1373 		return DOWN;
1374 	case DOWN:
1375 		return UP;
1376 	case LEFT:
1377 		return RIGHT;
1378 	case RIGHT:
1379 		return LEFT;
1380 	default:
1381 		return dir;
1382 	}
1383 }
1384 
1385 /* Mouvement � faire si je suis coinc� entre deux cases */
1386 int
decoince(int dir)1387 decoince (int dir)
1388 {
1389 	static int compteur = 0;
1390 	int nouv_dir = GoDefault;
1391 
1392 	/* Pour �viter de gigoter entre 2 bombes */
1393 	compteur++;
1394 	if (compteur > 4) {
1395 		compteur = 0;
1396 		nouv_dir = dir;
1397 	}
1398 
1399 	return nouv_dir;
1400 }
1401 
1402 /* Retourne VRAI si je peux tuer des ennemis */
1403 int
repose_en_mourant(BMPlayer * ps)1404 repose_en_mourant (BMPlayer * ps)
1405 {
1406 	int mazex, mazey;
1407 	int portee_bombe;
1408 
1409 	mazex = (int)(ps->x + 0.5 * BLOCK_WIDTH) / BLOCK_WIDTH;
1410 	mazey = (int)(ps->y + 0.5 * BLOCK_HEIGHT) / BLOCK_HEIGHT + 1;
1411 	portee_bombe = (ps->illness == IllMini) ? 1 : ps->range;
1412 
1413 	if (score_tue (mazex, mazey, portee_bombe) >= 0 && nb_ennemis_vivants > 0)
1414 		return XBTrue;
1415 	else
1416 		return XBFalse;
1417 }
1418 
1419 void
gestionBot(BMPlayer * player_stat,PlayerAction * player_action,int numero_bot,int num_player)1420 gestionBot (BMPlayer * player_stat, PlayerAction * player_action, int numero_bot, int num_player)
1421 {
1422 	int i, j;
1423 	int max = MALUS_MORT;
1424 	int choice = -1;
1425 	int mazex, mazey;
1426 	int inverse;
1427 	BMPlayer *ps;
1428 	PlayerAction *pa;
1429 	/* Fouf lenteur -- *//*  trace = 0; */
1430 
1431 	/* Fouf lenteur ++ *//* fprintf(stderr, "gestionBot\n"); */
1432 	/* Fouf lenteur ++ *//* fflush(stderr); */
1433 
1434 	ps = player_stat + numero_bot;
1435 	pa = player_action + numero_bot;
1436 	statut_joueurs = player_stat;
1437 	num_bot = numero_bot;
1438 	nb_joueurs = num_player;
1439 
1440 	mazex = ps->x / BLOCK_WIDTH;
1441 	mazey = ps->y / BLOCK_HEIGHT + 1;
1442 
1443 	/* Suis-je rapide ? */
1444 	if (ps->illness == IllRun)
1445 		duree_deplacement = FAST_SPEED;
1446 	else /* Suis-je Lent ? */ if (ps->illness == IllSlow)
1447 		duree_deplacement = SLOW_SPEED;
1448 	else
1449 		duree_deplacement = NORMAL_SPEED;
1450 
1451 	temps_jeu = gameTime;
1452 	/* D�but d'un niveau */
1453 	if (temps_jeu == 1)
1454 		init_laby_shrink ();
1455 
1456 	/* Suis-je invers� ? */
1457 	if (ps->illness == IllReverse)
1458 		inverse = XBTrue;
1459 	else
1460 		inverse = XBFalse;
1461 
1462 	/* Si je me trouve entre deux cases */
1463 	/* Fouf lenteur -- *//*  if ((ps->x % BLOCK_WIDTH) != 0 || (ps->y % BLOCK_HEIGHT) != 0) */
1464 /* Fouf lenteur ++ */ if (((ps->x % BLOCK_WIDTH) != 0 || (ps->y % BLOCK_HEIGHT) != 0)
1465 						  || ((ps->d_ist == GoStop) && (temps_jeu % 3))) {
1466 		switch (ps->d_ist) {
1467 		case GoUp:
1468 			/* kick si est possible */
1469 			if (CheckBomb (mazex, mazey) && !(ps->kick && CheckMazeFree2 (mazex, mazey - 1)))
1470 				pa->dir = decoince (GoDown);
1471 			break;
1472 		case GoDown:
1473 			if (CheckBomb (mazex, mazey + 1) && !(ps->kick && CheckMazeFree2 (mazex, mazey + 2)))
1474 				pa->dir = decoince (GoUp);
1475 			break;
1476 		case GoLeft:
1477 			if (CheckBomb (mazex, mazey) && !(ps->kick && CheckMazeFree2 (mazex - 1, mazey)))
1478 				pa->dir = decoince (GoRight);
1479 			break;
1480 		case GoRight:
1481 			if (CheckBomb (mazex + 1, mazey) && !(ps->kick && CheckMazeFree2 (mazex + 2, mazey)))
1482 				pa->dir = decoince (GoLeft);
1483 			break;
1484 		default:
1485 			break;
1486 		}
1487 		/* Si je meurs, je pose */
1488 		if (ps->dying)
1489 			pa->bomb = repose_en_mourant (ps);
1490 		if (inverse)
1491 			pa->dir = inversion (pa->dir);
1492 		return;
1493 	}
1494 
1495 	if (pa->dir == GoStop && !(temps_jeu & 1))
1496 		return;
1497 
1498 	/* Initialisation */
1499 	for (i = 0; i < NB_DIR; i++)
1500 		vote[i] = 0;
1501 
1502 	test_murs (ps);				/* Don't walk into walls ... */
1503 
1504 	/* Choix de la bonne direction et des actions � effectuer */
1505 	actions (ps);
1506 
1507 	/*  getBonuses (ps);
1508 	   putBombs (ps);  break the walls ... */
1509 	/*  randChoice (); */
1510 
1511 	for (j = 0; j < NB_DIR; j++)
1512 		if (vote[j] > max) {
1513 			/* Fouf lenteur -- *//*    if (trace) printf ("Ok for %d %d\n", j, vote[j]); */
1514 			max = vote[j];
1515 			choice = j;
1516 		}
1517 	/* Fouf lenteur -- *//*   else */
1518 	/* Fouf lenteur -- *//*      if (trace) printf ("Not ok for %d %d\n", j, vote[j]); */
1519 
1520 	switch (choice) {
1521 	case STOP:
1522 		/* Fouf lenteur -- *//* pa->dir = GoStop; */
1523 /* Fouf lenteur ++ */ if (ps->d_ist == GoStop) {
1524 /* Fouf lenteur ++ */ pa->dir = GoDefault;
1525 			/* Fouf lenteur ++ *//* fprintf(stderr, "GoDefault (already stop)\n"); */
1526 /* Fouf lenteur ++ */ }
1527 		else {
1528 /* Fouf lenteur ++ */ pa->dir = GoStop;
1529 			/* Fouf lenteur ++ *//* fprintf(stderr, "GoStop (stop NOW *********)\n"); */
1530 /* Fouf lenteur ++ */ }
1531 		break;
1532 	case UP:
1533 		pa->dir = GoUp;
1534 		/* Fouf lenteur ++ *//* fprintf(stderr, "GoUp\n"); */
1535 		break;
1536 	case LEFT:
1537 		pa->dir = GoLeft;
1538 		/* Fouf lenteur ++ *//* fprintf(stderr, "GoLeft\n"); */
1539 		break;
1540 	case DOWN:
1541 		pa->dir = GoDown;
1542 		/* Fouf lenteur ++ *//* fprintf(stderr, "GoDown\n"); */
1543 		break;
1544 	case RIGHT:
1545 		pa->dir = GoRight;
1546 		/* Fouf lenteur ++ *//* fprintf(stderr, "GoRight\n"); */
1547 		break;
1548 	}
1549 	/* Fouf lenteur ++ *//* fflush(stderr); */
1550 
1551 	/* Ai-je d�cid� de poser ? */
1552 	if (vote_poser)
1553 		pa->bomb = XBTrue;
1554 
1555 	/* Ai-je d�cid� de faire une action sp�ciale ? */
1556 	if (vote_action_speciale)
1557 		pa->special = XBTrue;
1558 
1559 	/* Ai-je envie de swapper ?
1560 	   if (vote_swap)
1561 	   pa->swap = XBTrue; */
1562 
1563 	if (inverse)
1564 		pa->dir = inversion (pa->dir);
1565 }
1566 
1567 /* BMFuncData :
1568 special_init : bonus EXTRA au d�part
1569 special_game : jeu sp�cial (bombes hant�es, lanc�es par les murs, ...)
1570 special_extra : bonus EXTRA � trouver
1571 special_key : action du +
1572 */
1573