/* * Biloba * Copyright (C) 2004-2005 Guillaume Demougeot, Colin Leroy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /** * Biloba - Q1 2005 * Game by Guillaume Demougeot * Code by Colin Leroy * * This file contains all functions related to tile * management. */ #include #include #include #include "utils.h" #include "tile.h" #include "pawn.h" #include "arrow.h" #include "logic.h" #ifdef DEBUG static char *tile_type_str(TileType type) { switch (type) { case TILE_NO_TILE: return "TILE_NO_TILE"; case TILE_NORMAL: return "TILE_NORMAL"; case TILE_CENTER: return "TILE_CENTER"; case TILE_UP_LEFT: return "TILE_UP_LEFT"; case TILE_UP_RIGHT: return "TILE_UP_RIGHT"; case TILE_DOWN_LEFT: return "TILE_DOWN_LEFT"; case TILE_DOWN_RIGHT: return "TILE_DOWN_RIGHT"; default: assert(FALSE); return "TILE_ERROR"; } } #endif static TileType tile_get_type(int x, int y) { if (x == 0 || x == MAX_TILES_X-1) { switch (y) { case 0: case MAX_TILES_Y-1: return TILE_NO_TILE; case 1: return (x==0 ? TILE_UP_LEFT:TILE_UP_RIGHT); case MAX_TILES_Y-2: return (x==0 ? TILE_DOWN_LEFT:TILE_DOWN_RIGHT); } } else if (x == 1 || x == MAX_TILES_X-2) { switch (y) { case 0: return (x==1 ? TILE_UP_LEFT:TILE_UP_RIGHT); case MAX_TILES_Y-1: return (x==1 ? TILE_DOWN_LEFT:TILE_DOWN_RIGHT); } } else if (x == (MAX_TILES_X-1)/2 && y == (MAX_TILES_Y-1)/2) return TILE_CENTER; return TILE_NORMAL; } static SDL_Surface *tiles_models[NUM_TILE_TYPES] = {NULL}; static LList *my_tiles = NULL; void init_tiles_models(void) { int i = 0; assert(tiles_models[TILE_NO_TILE] == NULL); tiles_models[TILE_NO_TILE] = biloba_load_image("tile-no-tile.png"); tiles_models[TILE_NORMAL] = biloba_load_image("tile.png"); tiles_models[TILE_CENTER] = biloba_load_image("tile-center.png"); tiles_models[TILE_UP_LEFT] = biloba_load_image("tile-up-left.png"); tiles_models[TILE_UP_RIGHT] = biloba_load_image("tile-up-right.png"); tiles_models[TILE_DOWN_LEFT] = biloba_load_image("tile-down-left.png"); tiles_models[TILE_DOWN_RIGHT] = biloba_load_image("tile-down-right.png"); for (i = 0; i < NUM_TILE_TYPES; i++) assert(tiles_models[i] != NULL); } static Tile *tile_find(int x, int y) { LList *cur = my_tiles; while (cur) { Tile *tile = (Tile *)cur->data; if (tile->pos_x == x && tile->pos_y == y) return tile; cur = cur->next; } return NULL; } Tile *tile_get(int x, int y) { Tile *new_tile = NULL; assert(x >= 0 && x < MAX_TILES_X); assert(y >= 0 && y < MAX_TILES_Y); #ifdef DEBUG printf("tile %d,%d: %s\n", x, y, tile_type_str(tile_get_type(x,y))); #endif if (tiles_models[TILE_NO_TILE] == NULL) init_tiles_models(); if (tile_find(x, y)) return tile_find(x, y); new_tile = malloc(sizeof(Tile)); new_tile->type = tile_get_type(x, y); new_tile->pos_x = x; new_tile->pos_y = y; new_tile->coord_x = get_x(x); new_tile->coord_y = get_y(y); new_tile->surface = tiles_models[new_tile->type]; new_tile->pawn = NULL; my_tiles = llist_append(my_tiles, new_tile); return new_tile; } void tile_free_all(void) { LList *tiles = my_tiles; for(; tiles; tiles = tiles->next) { Tile *tile = (Tile *)tiles->data; free(tile); tile = NULL; } llist_free(my_tiles); my_tiles = NULL; } Tile *tile_get_by_coords (int x, int y) { int nx = (x - X_OFFSET)/50; int ny = (y - Y_OFFSET)/50; #ifdef DEBUG printf("tile_get_by_coords: %d,%d -> %d,%d\n", x, y, nx, ny); #endif if (nx < 0 || nx >= MAX_TILES_X) return NULL; if (ny < 0 || ny >= MAX_TILES_Y) return NULL; return tile_get(nx, ny); } static void tile_draw_fast (Tile *tile, int fast) { assert(tile != NULL); put_image(tile->surface, tile->coord_x, tile->coord_y); if (tile->pawn) pawn_draw(tile->pawn); if (!fast) SDL_UpdateRect(screen, tile->coord_x, tile->coord_y, 50, 50); } void tile_draw (Tile *tile) { tile_draw_fast(tile, !is_playing()); } int tile_is_forward(Tile *tile, Tile *third) { if (!tile->pawn || third->pawn) return FALSE; if (game_num_players() > 2) { switch (tile->pawn->color) { case PAWN_ORANGE: return (third->pos_y >= tile->pos_y); case PAWN_BLUE: return (third->pos_x <= tile->pos_x); case PAWN_RED: return (third->pos_y <= tile->pos_y); case PAWN_GREEN: return (third->pos_x >= tile->pos_x); default: assert(FALSE); } } else { switch (tile->pawn->color) { case PAWN_ORANGE: return (third->pos_y >= tile->pos_y); case PAWN_BLUE: return (third->pos_y <= tile->pos_y); default: assert(FALSE); } } return FALSE; } LList *tile_get_accessible_surroundings (Tile *tile) { LList *results = NULL; int ox, x = tile->pos_x - 1; int oy, y = tile->pos_y - 1; if (x < 0) x = 0; if (y < 0) y = 0; ox = x; oy = y; #ifdef DEBUG printf("getting surroundings from %d, %d to %d, %d\n", x, y, min(tile->pos_x + 1, MAX_TILES_X), min(tile->pos_y + 1, MAX_TILES_Y)); #endif for (x = ox; x <= min(tile->pos_x + 1, MAX_TILES_X - 1); x++) { for (y = oy; y <= min(tile->pos_y + 1, MAX_TILES_Y - 1); y++) { Tile *ctile = tile_get(x, y); #ifdef DEBUG printf("tile_get_accessible_surroundings: tile %d,%d (%s): has_pawn %d.\n", ctile->pos_x, ctile->pos_y, tile_type_str(ctile->type), ctile->pawn != NULL); #endif if (ctile == tile) continue; if (ctile->type == TILE_NO_TILE || ctile->type == TILE_UP_LEFT || ctile->type == TILE_UP_RIGHT || ctile->type == TILE_DOWN_LEFT || ctile->type == TILE_DOWN_RIGHT) continue; if (ctile->pawn == NULL) { if (x == 4 && y == 4 && !can_move_on_center()) continue; results = llist_append(results, ctile); } else { Tile *third = tile_get_next_in_row(tile, ctile); if (third == NULL || third->pawn != NULL) continue; if (third->type == TILE_NO_TILE || third->type == TILE_UP_LEFT || third->type == TILE_UP_RIGHT || third->type == TILE_DOWN_LEFT || third->type == TILE_DOWN_RIGHT) continue; /* can't jump backward */ if (!tile_is_forward(tile, third)) continue; /* can't jump to center */ if (third->type == TILE_CENTER) continue; /* can't jump from center either */ if (tile->type == TILE_CENTER) continue; results = llist_append(results, ctile); /* just for repaint */ results = llist_append(results, third); } } } return results; } void tile_highlight(Tile *tile, int value) { static SDL_Surface *highlighter = NULL; if (!highlighter) { highlighter = biloba_load_image("highlighter.png"); assert(highlighter != NULL); } SDL_SetAlpha(highlighter, SDL_SRCALPHA, value); assert(tile != NULL); tile_draw_fast(tile, TRUE); if (value) put_image(highlighter, tile->coord_x, tile->coord_y); if (is_playing()) { SDL_UpdateRect(screen, tile->coord_x, tile->coord_y, 50, 50); } } void tile_draw_arrow(Tile *tile, Tile *to) { int start_x = tile->coord_x + 25; int start_y = tile->coord_y + 25; int offset_x = -10; int offset_y = -10; int left_to_right = 0; int up_to_down = 0; ArrowType arrow_type = -1; if (tile->coord_x < to->coord_x) { offset_x = +ARROW_OFFSET_FROM_CENTER; left_to_right = +1; } if (tile->coord_x > to->coord_x) { offset_x = -ARROW_OFFSET_FROM_CENTER - 20; left_to_right = -1; } if (tile->coord_y < to->coord_y) { offset_y = +ARROW_OFFSET_FROM_CENTER; up_to_down = -1; } if (tile->coord_y > to->coord_y) { offset_y = -ARROW_OFFSET_FROM_CENTER - 20; up_to_down = +1; } switch (left_to_right) { case +1: /* -> */ switch(up_to_down) { case +1: /* ^ */ arrow_type = ARROW_UP_RIGHT; break; case 0: /* . */ arrow_type = ARROW_RIGHT; break; case -1: /* v */ arrow_type = ARROW_DOWN_RIGHT; break; } break; case 0: /* . */ switch(up_to_down) { case +1: /* ^ */ arrow_type = ARROW_UP; break; case 0: /* . */ assert(FALSE); break; case -1: /* v */ arrow_type = ARROW_DOWN; break; } break; case -1: /* <- */ switch(up_to_down) { case +1: /* ^ */ arrow_type = ARROW_UP_LEFT; break; case 0: /* . */ arrow_type = ARROW_LEFT; break; case -1: /* v */ arrow_type = ARROW_DOWN_LEFT; break; } break; } assert(arrow_type != -1); arrow_draw(arrow_type, start_x + offset_x, start_y + offset_y); } Tile *tile_get_next_in_row(Tile *start, Tile *second) { int diff_x = second->pos_x - start->pos_x; int diff_y = second->pos_y - start->pos_y; int third_x = second->pos_x + diff_x; int third_y = second->pos_y + diff_y; if (third_x < 0 || third_x >= MAX_TILES_X) return NULL; if (third_y < 0 || third_y >= MAX_TILES_Y) return NULL; return tile_get(third_x, third_y); } int tile_is_near_center(Tile *tile) { LList *surr = tile_get_accessible_surroundings(tile); LList *cur = surr; while (cur) { Tile *t = (Tile *)cur->data; if (t->type == TILE_CENTER) { llist_free(surr); return TRUE; } cur = cur->next; } llist_free(surr); return FALSE; }