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