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 functions related to tile
26 * management.
27 */
28
29 #include <SDL.h>
30 #include <SDL_image.h>
31 #include <stdlib.h>
32
33 #include "utils.h"
34 #include "tile.h"
35 #include "pawn.h"
36 #include "arrow.h"
37 #include "logic.h"
38
39 #ifdef DEBUG
tile_type_str(TileType type)40 static char *tile_type_str(TileType type)
41 {
42 switch (type) {
43 case TILE_NO_TILE:
44 return "TILE_NO_TILE";
45 case TILE_NORMAL:
46 return "TILE_NORMAL";
47 case TILE_CENTER:
48 return "TILE_CENTER";
49 case TILE_UP_LEFT:
50 return "TILE_UP_LEFT";
51 case TILE_UP_RIGHT:
52 return "TILE_UP_RIGHT";
53 case TILE_DOWN_LEFT:
54 return "TILE_DOWN_LEFT";
55 case TILE_DOWN_RIGHT:
56 return "TILE_DOWN_RIGHT";
57 default:
58 assert(FALSE);
59 return "TILE_ERROR";
60 }
61 }
62 #endif
tile_get_type(int x,int y)63 static TileType tile_get_type(int x, int y)
64 {
65 if (x == 0 || x == MAX_TILES_X-1) {
66 switch (y) {
67 case 0:
68 case MAX_TILES_Y-1:
69 return TILE_NO_TILE;
70 case 1:
71 return (x==0 ? TILE_UP_LEFT:TILE_UP_RIGHT);
72 case MAX_TILES_Y-2:
73 return (x==0 ? TILE_DOWN_LEFT:TILE_DOWN_RIGHT);
74 }
75 } else if (x == 1 || x == MAX_TILES_X-2) {
76 switch (y) {
77 case 0:
78 return (x==1 ? TILE_UP_LEFT:TILE_UP_RIGHT);
79 case MAX_TILES_Y-1:
80 return (x==1 ? TILE_DOWN_LEFT:TILE_DOWN_RIGHT);
81 }
82 } else if (x == (MAX_TILES_X-1)/2 && y == (MAX_TILES_Y-1)/2)
83 return TILE_CENTER;
84
85 return TILE_NORMAL;
86 }
87
88 static SDL_Surface *tiles_models[NUM_TILE_TYPES] = {NULL};
89 static LList *my_tiles = NULL;
90
init_tiles_models(void)91 static void init_tiles_models(void)
92 {
93 int i = 0;
94 assert(tiles_models[TILE_NO_TILE] == NULL);
95
96 tiles_models[TILE_NO_TILE] = biloba_load_image("tile-no-tile.png");
97 tiles_models[TILE_NORMAL] = biloba_load_image("tile.png");
98 tiles_models[TILE_CENTER] = biloba_load_image("tile-center.png");
99 tiles_models[TILE_UP_LEFT] = biloba_load_image("tile-up-left.png");
100 tiles_models[TILE_UP_RIGHT] = biloba_load_image("tile-up-right.png");
101 tiles_models[TILE_DOWN_LEFT] = biloba_load_image("tile-down-left.png");
102 tiles_models[TILE_DOWN_RIGHT] = biloba_load_image("tile-down-right.png");
103
104 for (i = 0; i < NUM_TILE_TYPES; i++)
105 assert(tiles_models[i] != NULL);
106 }
107
tile_find(int x,int y)108 static Tile *tile_find(int x, int y)
109 {
110 LList *cur = my_tiles;
111
112 while (cur) {
113 Tile *tile = (Tile *)cur->data;
114 if (tile->pos_x == x && tile->pos_y == y)
115 return tile;
116 cur = cur->next;
117 }
118 return NULL;
119 }
120
tile_get(int x,int y)121 Tile *tile_get(int x, int y)
122 {
123 Tile *new_tile = NULL;
124
125 assert(x >= 0 && x < MAX_TILES_X);
126 assert(y >= 0 && y < MAX_TILES_Y);
127 #ifdef DEBUG
128 printf("tile %d,%d: %s\n", x, y, tile_type_str(tile_get_type(x,y)));
129 #endif
130 if (tiles_models[TILE_NO_TILE] == NULL)
131 init_tiles_models();
132
133 if (tile_find(x, y))
134 return tile_find(x, y);
135
136 new_tile = malloc(sizeof(Tile));
137
138 new_tile->type = tile_get_type(x, y);
139 new_tile->pos_x = x;
140 new_tile->pos_y = y;
141 new_tile->coord_x = get_x(x);
142 new_tile->coord_y = get_y(y);
143 new_tile->surface = tiles_models[new_tile->type];
144 new_tile->pawn = NULL;
145
146 my_tiles = llist_append(my_tiles, new_tile);
147
148 return new_tile;
149 }
150
tile_free_all(void)151 void tile_free_all(void)
152 {
153 LList *tiles = my_tiles;
154 for(; tiles; tiles = tiles->next) {
155 Tile *tile = (Tile *)tiles->data;
156 free(tile);
157 tile = NULL;
158 }
159 llist_free(my_tiles);
160 my_tiles = NULL;
161 }
162
tile_get_by_coords(int x,int y)163 Tile *tile_get_by_coords (int x, int y)
164 {
165 int nx = (x - X_OFFSET)/50;
166 int ny = (y - Y_OFFSET)/50;
167
168 #ifdef DEBUG
169 printf("tile_get_by_coords: %d,%d -> %d,%d\n", x, y, nx, ny);
170 #endif
171 if (nx < 0 || nx >= MAX_TILES_X)
172 return NULL;
173 if (ny < 0 || ny >= MAX_TILES_Y)
174 return NULL;
175
176 return tile_get(nx, ny);
177 }
178
tile_draw_fast(Tile * tile,int fast)179 static void tile_draw_fast (Tile *tile, int fast)
180 {
181 assert(tile != NULL);
182 put_image(tile->surface, tile->coord_x, tile->coord_y);
183
184 if (tile->pawn)
185 pawn_draw(tile->pawn);
186 if (!fast)
187 SDL_UpdateRect(screen, tile->coord_x, tile->coord_y, 50, 50);
188 }
189
tile_draw(Tile * tile)190 void tile_draw (Tile *tile)
191 {
192 tile_draw_fast(tile, !is_playing());
193 }
194
tile_is_forward(Tile * tile,Tile * third)195 static int tile_is_forward(Tile *tile, Tile *third)
196 {
197 if (!tile->pawn || third->pawn)
198 return FALSE;
199
200 if (game_num_players() > 2) {
201 switch (tile->pawn->color) {
202 case PAWN_ORANGE:
203 return (third->pos_y >= tile->pos_y);
204 case PAWN_BLUE:
205 return (third->pos_x <= tile->pos_x);
206 case PAWN_RED:
207 return (third->pos_y <= tile->pos_y);
208 case PAWN_GREEN:
209 return (third->pos_x >= tile->pos_x);
210 default:
211 assert(FALSE);
212 }
213 } else {
214 switch (tile->pawn->color) {
215 case PAWN_ORANGE:
216 return (third->pos_y >= tile->pos_y);
217 case PAWN_BLUE:
218 return (third->pos_y <= tile->pos_y);
219 default:
220 assert(FALSE);
221 }
222 }
223 return FALSE;
224 }
225
tile_get_accessible_surroundings(Tile * tile)226 LList *tile_get_accessible_surroundings (Tile *tile)
227 {
228 LList *results = NULL;
229 int ox, x = tile->pos_x - 1;
230 int oy, y = tile->pos_y - 1;
231
232 if (x < 0)
233 x = 0;
234 if (y < 0)
235 y = 0;
236
237 ox = x; oy = y;
238 #ifdef DEBUG
239 printf("getting surroundings from %d, %d to %d, %d\n",
240 x, y, min(tile->pos_x + 1, MAX_TILES_X),
241 min(tile->pos_y + 1, MAX_TILES_Y));
242 #endif
243 for (x = ox; x <= min(tile->pos_x + 1, MAX_TILES_X - 1); x++) {
244 for (y = oy; y <= min(tile->pos_y + 1, MAX_TILES_Y - 1); y++) {
245 Tile *ctile = tile_get(x, y);
246 #ifdef DEBUG
247 printf("tile_get_accessible_surroundings: tile %d,%d (%s): has_pawn %d.\n",
248 ctile->pos_x, ctile->pos_y,
249 tile_type_str(ctile->type),
250 ctile->pawn != NULL);
251 #endif
252 if (ctile == tile)
253 continue;
254 if (ctile->type == TILE_NO_TILE ||
255 ctile->type == TILE_UP_LEFT ||
256 ctile->type == TILE_UP_RIGHT ||
257 ctile->type == TILE_DOWN_LEFT ||
258 ctile->type == TILE_DOWN_RIGHT)
259 continue;
260
261 if (ctile->pawn == NULL) {
262 if (x == 4 && y == 4 && !can_move_on_center())
263 continue;
264 results = llist_append(results, ctile);
265 } else {
266 Tile *third = tile_get_next_in_row(tile, ctile);
267
268 if (third == NULL || third->pawn != NULL)
269 continue;
270
271 if (third->type == TILE_NO_TILE ||
272 third->type == TILE_UP_LEFT ||
273 third->type == TILE_UP_RIGHT ||
274 third->type == TILE_DOWN_LEFT ||
275 third->type == TILE_DOWN_RIGHT)
276 continue;
277
278 /* can't jump backward */
279 if (!tile_is_forward(tile, third))
280 continue;
281
282 /* can't jump to center */
283 if (third->type == TILE_CENTER)
284 continue;
285
286 /* can't jump from center either */
287 if (tile->type == TILE_CENTER)
288 continue;
289
290 results = llist_append(results, ctile); /* just for repaint */
291 results = llist_append(results, third);
292 }
293 }
294 }
295
296 return results;
297 }
298
tile_highlight(Tile * tile,int value)299 void tile_highlight(Tile *tile, int value)
300 {
301 static SDL_Surface *highlighter = NULL;
302
303 if (!highlighter) {
304 highlighter = biloba_load_image("highlighter.png");
305 assert(highlighter != NULL);
306 }
307 SDL_SetAlpha(highlighter, SDL_SRCALPHA, value);
308
309 assert(tile != NULL);
310
311 tile_draw_fast(tile, TRUE);
312
313 if (value)
314 put_image(highlighter,
315 tile->coord_x,
316 tile->coord_y);
317
318 if (is_playing()) {
319 SDL_UpdateRect(screen, tile->coord_x,
320 tile->coord_y, 50, 50);
321 }
322 }
323
tile_draw_arrow(Tile * tile,Tile * to)324 void tile_draw_arrow(Tile *tile, Tile *to)
325 {
326 int start_x = tile->coord_x + 25;
327 int start_y = tile->coord_y + 25;
328 int offset_x = -10;
329 int offset_y = -10;
330 int left_to_right = 0;
331 int up_to_down = 0;
332 ArrowType arrow_type = -1;
333 if (tile->coord_x < to->coord_x) {
334 offset_x = +ARROW_OFFSET_FROM_CENTER;
335 left_to_right = +1;
336 }
337 if (tile->coord_x > to->coord_x) {
338 offset_x = -ARROW_OFFSET_FROM_CENTER - 20;
339 left_to_right = -1;
340 }
341 if (tile->coord_y < to->coord_y) {
342 offset_y = +ARROW_OFFSET_FROM_CENTER;
343 up_to_down = -1;
344 }
345 if (tile->coord_y > to->coord_y) {
346 offset_y = -ARROW_OFFSET_FROM_CENTER - 20;
347 up_to_down = +1;
348 }
349
350 switch (left_to_right) {
351 case +1: /* -> */
352 switch(up_to_down) {
353 case +1: /* ^ */
354 arrow_type = ARROW_UP_RIGHT;
355 break;
356 case 0: /* . */
357 arrow_type = ARROW_RIGHT;
358 break;
359 case -1: /* v */
360 arrow_type = ARROW_DOWN_RIGHT;
361 break;
362 }
363 break;
364 case 0: /* . */
365 switch(up_to_down) {
366 case +1: /* ^ */
367 arrow_type = ARROW_UP;
368 break;
369 case 0: /* . */
370 assert(FALSE);
371 break;
372 case -1: /* v */
373 arrow_type = ARROW_DOWN;
374 break;
375 }
376 break;
377 case -1: /* <- */
378 switch(up_to_down) {
379 case +1: /* ^ */
380 arrow_type = ARROW_UP_LEFT;
381 break;
382 case 0: /* . */
383 arrow_type = ARROW_LEFT;
384 break;
385 case -1: /* v */
386 arrow_type = ARROW_DOWN_LEFT;
387 break;
388 }
389 break;
390 }
391 assert(arrow_type != -1);
392
393 arrow_draw(arrow_type, start_x + offset_x, start_y + offset_y);
394 }
395
tile_get_next_in_row(Tile * start,Tile * second)396 Tile *tile_get_next_in_row(Tile *start, Tile *second)
397 {
398 int diff_x = second->pos_x - start->pos_x;
399 int diff_y = second->pos_y - start->pos_y;
400 int third_x = second->pos_x + diff_x;
401 int third_y = second->pos_y + diff_y;
402
403 if (third_x < 0 || third_x >= MAX_TILES_X)
404 return NULL;
405 if (third_y < 0 || third_y >= MAX_TILES_Y)
406 return NULL;
407 return tile_get(third_x, third_y);
408 }
409
tile_is_near_center(Tile * tile)410 int tile_is_near_center(Tile *tile)
411 {
412 LList *surr = tile_get_accessible_surroundings(tile);
413 LList *cur = surr;
414 while (cur) {
415 Tile *t = (Tile *)cur->data;
416 if (t->type == TILE_CENTER) {
417 llist_free(surr);
418 return TRUE;
419 }
420 cur = cur->next;
421 }
422 llist_free(surr);
423 return FALSE;
424 }
425