1 /*
2  * Biloba
3  * Copyright (C) 2004-2008 Guillaume Demougeot, Colin Leroy
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 /**
21  * Biloba - Q1 2005
22  * Game by Guillaume Demougeot <dmgt@wanadoo.fr>
23  * Code by Colin Leroy <colin@colino.net>
24  *
25  * This file contains all pawn management code.
26  */
27 
28 #include <SDL.h>
29 #include <SDL_image.h>
30 #include <stdlib.h>
31 #include "utils.h"
32 #include "tile.h"
33 #include "pawn.h"
34 #include "layout.h"
35 #include "sound.h"
36 
pawn_get_max(void)37 int pawn_get_max(void)
38 {
39 	switch(game_num_players()) {
40 	case 2:
41 		return 16;
42 	case 3:
43 	case 4:
44 		return 8;
45 	default:
46 		assert(FALSE);
47 		return -1;
48 	}
49 }
50 
51 #ifdef DEBUG
pawn_color_str(PawnColor color)52 char *pawn_color_str(PawnColor color)
53 {
54 	assert(color >= 0 && color < PAWN_NUM_COLORS);
55 	switch(color) {
56 	case PAWN_ORANGE:
57 		return "PAWN_ORANGE";
58 	case PAWN_BLUE:
59 		return "PAWN_BLUE";
60 	case PAWN_RED:
61 		return "PAWN_RED";
62 	case PAWN_GREEN:
63 		return "PAWN_GREEN";
64 	default:
65 		assert(FALSE);
66 		return "PAWN_ERROR";
67 	}
68 }
69 #endif
70 
71 static SDL_Surface *pawns_models[PAWN_NUM_COLORS] = {NULL};
72 static LList *my_pawns = NULL;
73 
init_pawns_models(void)74 static void init_pawns_models(void)
75 {
76 	int i = 0;
77 	assert(pawns_models[0] == NULL);
78 
79 	pawns_models[PAWN_ORANGE] = biloba_load_image("pawn-orange.png");
80 	pawns_models[PAWN_BLUE]   = biloba_load_image("pawn-blue.png");
81 	pawns_models[PAWN_RED]    = biloba_load_image("pawn-red.png");
82 	pawns_models[PAWN_GREEN]  = biloba_load_image("pawn-green.png");
83 
84 	for (i = 0; i < PAWN_NUM_COLORS; i++)
85 		assert(pawns_models[i] != NULL);
86 }
87 
88 
pawn_find(int num,PawnColor color)89 static Pawn *pawn_find(int num, PawnColor color)
90 {
91 	LList *cur = my_pawns;
92 
93 	while (cur) {
94 		Pawn *pawn = (Pawn *)cur->data;
95 		if (pawn->num == num && pawn->color == color)
96 			return pawn;
97 		cur = cur->next;
98 	}
99 	return NULL;
100 }
101 
pawn_count(PawnColor color)102 int pawn_count(PawnColor color)
103 {
104 	LList *cur = my_pawns;
105 	int cnt = 0;
106 
107 	while (cur) {
108 		Pawn *pawn = (Pawn *)cur->data;
109 		if (!pawn->eaten && pawn->color == color)
110 			cnt++;
111 		cur = cur->next;
112 	}
113 
114 	return cnt;
115 }
116 
pawn_get_all(PawnColor color)117 LList *pawn_get_all(PawnColor color)
118 {
119 	LList *cur = my_pawns;
120 	LList *results = NULL;
121 
122 	while (cur) {
123 		Pawn *pawn = (Pawn *)cur->data;
124 		if (!pawn->eaten && pawn->color == color)
125 			results = llist_append(results, pawn);
126 		cur = cur->next;
127 	}
128 
129 	return results;
130 }
131 
pawn_get_coords(int num,PawnColor color,int * x,int * y)132 static void pawn_get_coords(int num, PawnColor color, int *x, int *y)
133 {
134 	int cnt = 0, tx = 0, ty = 0;
135 
136 	assert(num >= 0 && num < pawn_get_max());
137 	assert(color >= 0 && color < PAWN_NUM_COLORS);
138 	assert(x != NULL);
139 	assert(y != NULL);
140 
141 	for (tx = 0; tx < MAX_TILES_X; tx++) {
142 		for (ty = 0; ty < MAX_TILES_Y; ty++) {
143 			if (game_num_players() == 2) {
144 				if (pos_2p[(int)color][ty][tx]) {
145 					if (cnt == num) {
146 						*x = tx;
147 						*y = ty;
148 						return;
149 					}
150 					cnt++;
151 				}
152 			} else {
153 				if (pos_4p[(int)color][ty][tx]) {
154 					if (cnt == num) {
155 						*x = tx;
156 						*y = ty;
157 						return;
158 					}
159 					cnt++;
160 				}
161 			}
162 		}
163 	}
164 	*x = -1;
165 	*y = -1;
166 }
167 
pawn_update_coords(Pawn * pawn)168 static void pawn_update_coords(Pawn *pawn)
169 {
170 	assert(pawn != NULL);
171 	pawn->coord_x	= get_x(pawn->pos_x) + PAWN_OFFSET;
172 	pawn->coord_y	= get_y(pawn->pos_y) + PAWN_OFFSET;
173 }
174 
pawn_get(int num,PawnColor color,int reinit)175 Pawn *pawn_get(int num, PawnColor color, int reinit)
176 {
177 	Pawn *new_pawn = NULL;
178 	int x = 0, y = 0;
179 	assert(num >= 0 && num < pawn_get_max());
180 	assert(color >= 0 && color < PAWN_NUM_COLORS);
181 #ifdef DEBUG
182 	printf("pawn %d, %s\n", num, pawn_color_str(color));
183 #endif
184 	if (pawns_models[PAWN_ORANGE] == NULL)
185 		init_pawns_models();
186 
187 	if (pawn_find(num, color))
188 		new_pawn = pawn_find(num, color);
189 	else {
190 		assert(reinit == TRUE);
191 		new_pawn = malloc(sizeof(Pawn));
192 		my_pawns = llist_append(my_pawns, new_pawn);
193 	}
194 
195 	if (reinit) {
196 		pawn_get_coords(num, color, &x, &y);
197 		new_pawn->num 		= num;
198 		new_pawn->color		= color;
199 		new_pawn->eaten		= FALSE;
200 		new_pawn->just_ate_on	= NULL;
201 		new_pawn->pos_x		= x;
202 		new_pawn->pos_y		= y;
203 		new_pawn->surface	= pawns_models[new_pawn->color];
204 		if (x >= 0 && y >= 0)
205 			tile_get(x, y)->pawn = new_pawn;
206 		else
207 			new_pawn->eaten	= TRUE;
208 
209 		pawn_update_coords(new_pawn);
210 	}
211 
212 	return new_pawn;
213 }
214 
pawn_free_all(void)215 void pawn_free_all(void)
216 {
217 	LList *pawns = my_pawns;
218 	for(; pawns; pawns = pawns->next) {
219 		Pawn *pawn = (Pawn *)pawns->data;
220 		free(pawn);
221 		pawn = NULL;
222 	}
223 	llist_free(my_pawns);
224 	my_pawns = NULL;
225 }
226 
pawn_draw(Pawn * pawn)227 void pawn_draw (Pawn *pawn)
228 {
229 	assert(pawn != NULL);
230 	put_image(pawn->surface, pawn->coord_x, pawn->coord_y);
231 }
232 
pawn_get_tile(Pawn * pawn)233 Tile *pawn_get_tile(Pawn *pawn)
234 {
235 	assert(pawn != NULL);
236 	if (pawn->eaten)
237 		return NULL;
238 
239 	return tile_get(pawn->pos_x, pawn->pos_y);
240 }
241 
pawn_get_surroundings(Tile * tile)242 LList *pawn_get_surroundings(Tile *tile)
243 {
244 	LList *results = NULL;
245 	int ox, x = tile->pos_x - 1;
246 	int oy, y = tile->pos_y - 1;
247 
248 	if (x < 0)
249 		x = 0;
250 	if (y < 0)
251 		y = 0;
252 
253 	ox = x; oy = y;
254 
255 	for (x = ox; x <= min(tile->pos_x + 1, MAX_TILES_X - 1); x++) {
256 		for (y = oy; y <= min(tile->pos_y + 1, MAX_TILES_Y - 1); y++) {
257 			Tile *ctile = tile_get(x, y);
258 			if (ctile == tile)
259 				continue;
260 			if (ctile->pawn)
261 				results = llist_append(results, ctile->pawn);
262 		}
263 	}
264 
265 	return results;
266 }
267 
pawn_highlight(Pawn * pawn,int value)268 static void pawn_highlight(Pawn *pawn, int value)
269 {
270 	static SDL_Surface *highlighter = NULL;
271 	Tile *tile = pawn_get_tile(pawn);
272 
273 	if (!highlighter) {
274 		highlighter = biloba_load_image("pawn-highlighter.png");
275 		assert(highlighter != NULL);
276 	}
277 	SDL_SetAlpha(highlighter, SDL_SRCALPHA, value);
278 
279 	assert(tile != NULL);
280 
281 	if (value)
282 		put_image(highlighter,
283 				tile->coord_x + PAWN_OFFSET,
284 				tile->coord_y + PAWN_OFFSET);
285 
286 	if (is_playing()) {
287 		SDL_UpdateRect(screen, tile->coord_x + PAWN_OFFSET,
288 				tile->coord_y + PAWN_OFFSET, 30, 30);
289 	}
290 }
291 
pawn_eat_fast(Pawn * pawn,int fast)292 void pawn_eat_fast(Pawn *pawn, int fast)
293 {
294 	Tile *tile = pawn_get_tile(pawn);
295 	int i = 0;
296 	assert(pawn->eaten == FALSE);
297 
298 	if (!fast)
299 		sound_play(SND_EAT);
300 
301 	for (i = SDL_ALPHA_TRANSPARENT; !fast && i < SDL_ALPHA_OPAQUE; i++) {
302 		pawn_highlight(pawn, i);
303 		SDL_Delay(5);
304 	}
305 	pawn->eaten = TRUE;
306 	tile->pawn = NULL;
307 	tile_draw(tile);
308 	if (!fast)
309 		pawn_show_eaten();
310 }
311 
pawn_eat(Pawn * pawn)312 void pawn_eat(Pawn *pawn)
313 {
314 	pawn_eat_fast(pawn, FALSE);
315 }
316 
pawn_try_and_eat(Pawn * start,Pawn * to_eat)317 int pawn_try_and_eat(Pawn *start, Pawn *to_eat)
318 {
319 	Tile *start_tile  = pawn_get_tile(start);
320 	Tile *to_eat_tile = pawn_get_tile(to_eat);
321 	Tile *third_tile = tile_get_next_in_row(start_tile, to_eat_tile);
322 	Pawn *third = NULL;
323 
324 	if (start->color == to_eat->color)
325 		return FALSE;
326 	if (third_tile == NULL)
327 		return FALSE;
328 
329 	if (third_tile->type == TILE_NO_TILE || third_tile->type == TILE_CENTER)
330 		return FALSE;
331 
332 	if (!third_tile->pawn)
333 		return FALSE;
334 
335 	third = third_tile->pawn;
336 
337 	if (third->color == start->color) {
338 #ifdef DEBUG
339 		printf("adding %d %d and %d %d\n",
340 				start->coord_x, start->coord_y,
341 				third->coord_x, third->coord_y);
342 #endif
343 		start->just_ate_on = llist_append(start->just_ate_on, to_eat_tile);
344 		third->just_ate_on = llist_append(third->just_ate_on, to_eat_tile);
345 		return TRUE;
346 	}
347 	return FALSE;
348 }
349 
pawn_move_to(Pawn * pawn,Tile * tile)350 void pawn_move_to(Pawn *pawn, Tile *tile)
351 {
352 	Tile *orig = NULL;
353 
354 	assert(pawn != NULL);
355 	assert(tile != NULL);
356 	assert(pawn->eaten == FALSE);
357 	assert(tile->pawn == NULL);
358 
359 	orig = pawn_get_tile(pawn);
360 	assert(orig != NULL);
361 
362 	orig->pawn = NULL;
363 	pawn->pos_x = tile->pos_x;
364 	pawn->pos_y = tile->pos_y;
365 	pawn_update_coords(pawn);
366 	tile->pawn = pawn;
367 
368 	tile_draw(orig);
369 	tile_draw(tile);
370 }
371 
pawn_get_replacement_pending_pawns(PawnColor color)372 LList *pawn_get_replacement_pending_pawns(PawnColor color)
373 {
374 	LList *results = NULL, *all = pawn_get_all(color);
375 	LList *cur = all;
376 
377 	while (cur) {
378 		Pawn *pawn = (Pawn *)cur->data;
379 		if (pawn->just_ate_on) {
380 			LList *tiles = pawn->just_ate_on;
381 			if (pawn->eaten) {
382 				/* pawn has been eaten, too bad!*/
383 				llist_free(pawn->just_ate_on);
384 				pawn->just_ate_on = NULL;
385 				continue;
386 			}
387 			while (tiles) {
388 				Tile *tile = (Tile *)tiles->data;
389 				if (tile->pawn) {
390 					pawn->just_ate_on = llist_remove(pawn->just_ate_on, tile);
391 					tiles = pawn->just_ate_on;
392 				}
393 				if (tiles)
394 					tiles = tiles->next;
395 			}
396 			if (pawn->just_ate_on) {
397 #ifdef DEBUG
398 				printf("pawn %d %d just ate\n", pawn->pos_x, pawn->pos_y);
399 #endif
400 				results = llist_append(results, pawn);
401 			}
402 
403 		}
404 		cur = cur->next;
405 	}
406 
407 	llist_free(all);
408 
409 	return results;
410 }
411 
pawn_remove_just_eaten(Tile * tile)412 void pawn_remove_just_eaten(Tile *tile)
413 {
414 	LList *cur = my_pawns;
415 
416 	while (cur) {
417 		Pawn *pawn = (Pawn *)cur->data;
418 		pawn->just_ate_on = llist_remove(pawn->just_ate_on, tile);
419 		cur = cur->next;
420 	}
421 }
422 
pawn_show_eaten(void)423 void pawn_show_eaten(void)
424 {
425 	int cur_eaten[4] = {0, 0, 0, 0};
426 	LList *cur = my_pawns;
427 
428 	for (; cur ; cur = cur->next) {
429 		Pawn *pawn = (Pawn *)cur->data;
430 		int offset = (35 * ((int)pawn->color + 1));
431 		int pos_x;
432 		int pos_y;
433 
434 		if ((int)pawn->color >= game_num_players())
435 			continue;
436 		if (pawn->num >= pawn_get_max())
437 			continue;
438 		if (!pawn->eaten)
439 			continue;
440 		cur_eaten[(int)pawn->color]++;
441 
442 		pos_x = XS - offset;
443 		pos_y = 10 + (35 * (cur_eaten[(int)pawn->color]-1));
444 		if (cur_eaten[(int)pawn->color] > pawn_get_max())
445 			continue;
446 #ifdef DEBUG
447 		printf("putting pawn at %d %d\n", pos_x, pos_y);
448 #endif
449 		put_image(pawn->surface, pos_x, pos_y);
450 	}
451 
452 	SDL_UpdateRect(screen, XS - 160, 0, 159, 599);
453 }
454