/* * 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 player management code. */ #include #include #include "utils.h" #include "player.h" #include "local_input.h" #include "net.h" #include "font.h" #include "computer.h" #include "logic.h" #include "msg.h" #include "sound.h" static LList *my_players = NULL; static Player *player_find(PawnColor color) { LList *cur = my_players; while (cur) { Player *p = (Player *)cur->data; if (p->color == color) return p; cur = cur->next; } return NULL; } Player *player_get(PawnColor color, int reinit, InputSystemMethod method) { Player *player = NULL; if (player_find(color)) player = player_find(color); else { assert(reinit == TRUE); player = malloc(sizeof(Player)); my_players = llist_append(my_players, player); } if (reinit) { player->color = color; player->method = method; player->name = NULL; } return player; } void player_set_name(Player *player, const char *name) { player->name = name; } LList *player_can_eat_soon(Player *player, int now_too, LList *allowed_pawns) { LList *eatables = NULL; LList *pawns = pawn_get_all(player->color); LList *cur = NULL; /* for each of player's pawns... */ for (cur = pawns; cur; cur = cur->next) { Pawn *cur_pawn = (Pawn *)cur->data; LList *surrounding = NULL; LList *surr_cur; if (allowed_pawns && !llist_find(allowed_pawns, cur_pawn)) continue; surrounding = pawn_get_surroundings(pawn_get_tile(cur_pawn)); /* see if it has an adjacent pawn... */ for (surr_cur = surrounding; surr_cur; surr_cur = surr_cur->next) { Pawn *surr_pawn = (Pawn *)surr_cur->data; Tile *third_tile = NULL; LList *third_list = NULL, *cur_third = NULL; /* ... and it is not the same color ... */ if (surr_pawn->color == cur_pawn->color) continue; /* ...get the third tile in a row, and check that * it is acceptable (exists, not center, empty) */ third_tile = tile_get_next_in_row (pawn_get_tile(cur_pawn), pawn_get_tile(surr_pawn)); if (third_tile == NULL) continue; if (third_tile->type == TILE_CENTER) continue; if (third_tile->pawn && !now_too) continue; else if (third_tile->pawn && now_too) { if (third_tile->pawn->color == cur_pawn->color && !llist_find(eatables, surr_pawn)) eatables = llist_append(eatables, surr_pawn); continue; } if (now_too) continue; /* Now get this third tile's surrounding to check * whether one of its neighbors is of the same as the * original pawn */ third_list = pawn_get_surroundings(third_tile); /* if it is near (adjacent to) center, its neighbors * comes from more far, go get them */ if (tile_is_near_center(third_tile)) { LList *pawns_near_center = pawn_get_surroundings(tile_get( MAX_TILES_X/2, MAX_TILES_Y/2)); LList *cur_near_center = pawns_near_center; while (cur_near_center) { third_list = llist_append(third_list, (Pawn *)cur_near_center->data); cur_near_center = cur_near_center->next; } llist_free(pawns_near_center); } /* now, check if one of these neighbors is of the * correct color and if it is, add it to the results */ for (cur_third = third_list; cur_third; cur_third = cur_third->next) { Pawn *third_pawn = (Pawn *)cur_third->data; if(third_pawn->color == cur_pawn->color && !llist_find(eatables, third_pawn)) { eatables = llist_append(eatables, third_pawn); #ifdef DEBUG printf("pawn %d,%d can eat %d,%d with %d,%d\n", cur_pawn->pos_x, cur_pawn->pos_y, surr_pawn->pos_x, surr_pawn->pos_y, third_pawn->pos_x, third_pawn->pos_y); #endif } } llist_free(third_list); } llist_free(surrounding); } llist_free(pawns); return eatables; } LList *player_can_be_eaten(Player *player, int now_too, LList *allowed_pawns) { LList *eatables = NULL; LList *pawns = pawn_get_all(player->color); LList *cur = NULL; /* for each of player's pawns... */ for (cur = pawns; cur; cur = cur->next) { Pawn *cur_pawn = (Pawn *)cur->data; LList *surrounding = NULL; LList *surr_cur; if (allowed_pawns && !llist_find(allowed_pawns, cur_pawn)) continue; surrounding = pawn_get_surroundings(pawn_get_tile(cur_pawn)); /* see if it has an adjacent pawn... */ for (surr_cur = surrounding; surr_cur; surr_cur = surr_cur->next) { Pawn *surr_pawn = (Pawn *)surr_cur->data; Tile *third_tile = NULL; LList *third_list = NULL, *cur_third = NULL; /* ... and it is not the same color ... */ if (surr_pawn->color == cur_pawn->color) continue; /* ...get the facing third tile, and check that * it is acceptable (exists, not center, same color as second) */ third_tile = tile_get_next_in_row (pawn_get_tile(surr_pawn), pawn_get_tile(cur_pawn)); if (third_tile == NULL) continue; if (third_tile->type == TILE_CENTER) continue; if (third_tile->pawn) { if (third_tile->pawn->color == surr_pawn->color && !llist_find(eatables, cur_pawn)) eatables = llist_append(eatables, cur_pawn); } /* Now get this third tile's surrounding to check * whether one of its neighbors is of the same as the * original pawn */ third_list = pawn_get_surroundings(third_tile); /* if it is near (adjacent to) center, its neighbors * comes from more far, go get them */ if (tile_is_near_center(third_tile)) { LList *pawns_near_center = pawn_get_surroundings(tile_get( MAX_TILES_X/2, MAX_TILES_Y/2)); LList *cur_near_center = pawns_near_center; while (cur_near_center) { third_list = llist_append(third_list, (Pawn *)cur_near_center->data); cur_near_center = cur_near_center->next; } llist_free(pawns_near_center); } /* now, check if one of these neighbors is of the * correct color and if it is, add it to the results */ for (cur_third = third_list; cur_third; cur_third = cur_third->next) { Pawn *third_pawn = (Pawn *)cur_third->data; if(third_pawn->color == surr_pawn->color && !llist_find(eatables, cur_pawn)) { eatables = llist_append(eatables, cur_pawn); #ifdef DEBUG printf("pawn %d,%d can be eaten by %d,%d and %d,%d\n", cur_pawn->pos_x, cur_pawn->pos_y, surr_pawn->pos_x, surr_pawn->pos_y, third_pawn->pos_x, third_pawn->pos_y); #endif #undef DEBUG } } llist_free(third_list); } llist_free(surrounding); } llist_free(pawns); return eatables; } static void player_kill(Player *player) { int i; char *msg; char num[2] = {((int)player->color)+1+'0', 0}; for (i = 0; i < game_num_players(); i++) { LList *pawns = pawn_get_all((PawnColor)i); for (; pawns; pawns = pawns->next) { Pawn *pawn = (Pawn *)pawns->data; if (!pawn->eaten) pawn_eat_fast(pawn, TRUE); } pawn_show_eaten(); } if (player->name == NULL) { msg = malloc(strlen(get_msg(M_PLAYER_LEAVES))+1); strcpy(msg, get_msg(M_PLAYER)); strcat(msg, num); strcat(msg, get_msg(M_LEAVES)); } else { msg = malloc(strlen(player->name) + strlen(get_msg(M_LEAVES)) + 1); strcpy(msg, player->name); strcat(msg, get_msg(M_LEAVES)); } clear_text(20/* max len, probably */, 20 + 50, YS - 50); draw_message(msg, 20 + 50, YS - 50, FALSE); SDL_Delay(1500); clear_text(strlen(msg), 20 + 50, YS - 50); free(msg); } Tile *player_select_tile(Player *player, LList *allowed) { Tile *result = NULL; int x = 0, y = 0; while (game_suspended()) { SDL_Delay(20); } if (game_ended()) return NULL; switch(player->method) { case INPUT_LOCAL: result = local_select_tile(); if (result) net_send_event(player->color, result->pos_x, result->pos_y); else net_send_event(player->color, -1, -1); break; case INPUT_AI: result = computer_select_tile(player, allowed); if (result) net_send_event(player->color, result->pos_x, result->pos_y); else net_send_event(player->color, -1, -1); break; case INPUT_NETWORK: do { net_get_event(player->color, &x, &y); #ifdef DEBUG printf("got event %d,%d\n", x,y); #endif SDL_Delay(200); if (x == -2 && y == -2) { player_kill(player); return NULL; } } while (x == -1 && y == -1); result = tile_get(x, y); break; default: assert(FALSE); } sound_play(SND_CLICK); return result; }