void get_bishop_moves(char board[BOARD_SIZE][BOARD_SIZE], COLOR player, Pos piece){ Pos curr; curr.col = piece.col + 1; curr.row = piece.row + 1; while (is_valid_pos(curr)){ if (is_valid_dest(board, player, curr) == 1 || is_valid_dest(board, player, curr) == 2) add_move(piece, curr, 0); if (is_valid_dest(board, player, curr) == 0 || is_valid_dest(board, player, curr) == 2) break; curr.col++, curr.row++; } curr.col = piece.col - 1; curr.row = piece.row - 1; while (is_valid_pos(curr)){ if (is_valid_dest(board, player, curr) == 1 || is_valid_dest(board, player, curr) == 2) add_move(piece, curr, 0); if (is_valid_dest(board, player, curr) == 0 || is_valid_dest(board, player, curr) == 2) break; curr.col--, curr.row--; } curr.col = piece.col - 1; curr.row = piece.row + 1; while (is_valid_pos(curr)){ if (is_valid_dest(board, player, curr) == 1 || is_valid_dest(board, player, curr) == 2) add_move(piece, curr, 0); if (is_valid_dest(board, player, curr) == 0 || is_valid_dest(board, player, curr) == 2) break; curr.col--, curr.row++; } curr.col = piece.col + 1; curr.row = piece.row - 1; while (is_valid_pos(curr)){ if (is_valid_dest(board, player, curr) == 1 || is_valid_dest(board, player, curr) == 2) add_move(piece, curr, 0); if (is_valid_dest(board, player, curr) == 0 || is_valid_dest(board, player, curr) == 2) break; curr.col++, curr.row--; } }
int get_capture_moves(Pos start, Pos piece, char board[BOARD_SIZE][BOARD_SIZE], COLOR player, int count, Pos* dests){ Pos pos[4] = { { piece.col - 1, piece.row - 1 }, { piece.col + 1, piece.row - 1 }, { piece.col - 1, piece.row + 1 }, { piece.col + 1, piece.row + 1 } }; int found_now = 0, found_ahead; for (int p = 0; p < 4; p++) if (is_valid_pos(pos[p]) && is_opposite(player, board[pos[p].col][pos[p].row])){ Pos new_piece = get_next_diag(piece, pos[p]); if (is_valid_pos(new_piece) && board[new_piece.col][new_piece.row] == EMPTY){ found_now++; char tmp = board[pos[p].col][pos[p].row]; board[pos[p].col][pos[p].row] = EMPTY; Pos* new_dests = malloc(sizeof(Pos) * (count + 1)); for (int i = 0; i < count; i++){ new_dests[i].row = dests[i].row; new_dests[i].col = dests[i].col; } new_dests[count].row = new_piece.row; new_dests[count].col = new_piece.col; found_ahead = get_capture_moves(start, new_piece, board, player, count + 1, new_dests); if (found_ahead == 0){ add_move(start, new_dests, count + 1); free(new_dests); } board[pos[p].row][pos[p].col] = tmp; } } return found_now; }
// finds all moves of a single king piece void get_king_moves(char board[BOARD_SIZE][BOARD_SIZE], COLOR player, Pos piece){ Pos pos[4] = { { piece.col - 1, piece.row - 1 }, { piece.col + 1, piece.row - 1 }, { piece.col - 1, piece.row + 1 }, { piece.col + 1, piece.row + 1 } }; Pos curr, new_piece; int found_ahead = -1; for (int p = 0; p < 4; p++){ curr = pos[p]; while (is_valid_pos(curr) && board[curr.col][curr.row] == EMPTY){ add_move(piece, &curr, 0); curr = get_next_diag(piece, curr); } if (is_valid_pos(curr) && is_opposite(player, board[curr.col][curr.row])){ char tmp = board[curr.col][curr.row]; board[curr.col][curr.row] = EMPTY; board[piece.col][piece.row] = EMPTY; new_piece = get_next_diag(piece, curr); if (is_valid_pos(new_piece) && board[new_piece.col][new_piece.row] == EMPTY){ found_ahead = get_capture_moves(piece, new_piece, board, player, 1, &new_piece); if (found_ahead == 0) add_move(piece, &new_piece, 1); } board[curr.col][curr.row] = tmp; board[piece.col][piece.row] = curr_piece; } } }
void get_king_moves(char board[BOARD_SIZE][BOARD_SIZE], COLOR player, Pos piece){ Move* res = NULL; Move* res_head = res; Pos pos[4] = { { piece.col - 1, piece.row - 1 }, { piece.col + 1, piece.row - 1 }, { piece.col - 1, piece.row + 1 }, { piece.col + 1, piece.row + 1 } }; Pos curr; int found_ahead; for (int p = 0; p < 4; p++){ curr = pos[p]; while (is_valid_pos(curr) && board[curr.col][curr.row] == EMPTY){ add_move(piece, &curr, 1); curr = get_next_diag(piece, curr); // BUG - once dests_num == 1 and |dest-start| != 1 add_moves thinks its 1 capture and not a simple move.. } if (is_valid_pos(curr) && is_opposite(player, board[curr.col][curr.row])){ char tmp = board[curr.row][curr.col]; board[curr.row][curr.col] = EMPTY; Pos new_piece = get_next_diag(piece, curr); if (is_valid_pos(new_piece) && board[new_piece.row][new_piece.col] == EMPTY){ found_ahead = get_capture_moves(piece, new_piece, board, player, 1, &new_piece); if (found_ahead == 0) add_move(piece, &new_piece, 1); } board[curr.row][curr.col] = tmp; } } }
static void place_in_initial_fall (struct anim *g) { struct pos pmt, pmtf, pmtb; struct pos fall_pos; int dirf = (g->f.dir == LEFT) ? -1 : +1; int dirb = (g->f.dir == LEFT) ? +1 : -1; survey (_mt, pos, &g->f, NULL, &pmt, NULL); prel (&pmt, &pmtf, +0, dirf); prel (&pmt, &pmtb, +0, dirb); invalid_pos (&fall_pos); if (is_strictly_traversable (&pmt)) fall_pos = pmt; else if (is_strictly_traversable (&pmtf)) fall_pos = pmtf; else if (is_strictly_traversable (&pmtb)) fall_pos = pmtb; struct frameset *frameset = get_guard_fall_frameset (g->type); if (is_valid_pos (&fall_pos)) place_frame (&g->f, &g->f, frameset[0].frame, &fall_pos, (g->f.dir == LEFT) ? PLACE_WIDTH - 12 : +6, (g->f.dir == LEFT) ? 23 : 27); }
bool peq (struct pos *p0, struct pos *p1) { struct pos np0, np1; if (! is_valid_pos (p0) || ! is_valid_pos (p1)) return false; npos (p0, &np0); npos (p1, &np1); return /* np0.l == np1.l && */ np0.room == np1.room && np0.floor == np1.floor && np0.place == np1.place; }
void get_man_moves(char board[BOARD_SIZE][BOARD_SIZE], COLOR player, Pos piece){ Move* res = NULL; Move* res_head = res; Pos pos[4] = { { piece.col - 1, piece.row - 1 }, { piece.col + 1, piece.row - 1 }, { piece.col - 1, piece.row + 1 }, { piece.col + 1, piece.row + 1 } }; int direction = 1, found_ahead; if (player == BLACK) direction = -1; for (int p = 0; p < 4; p++){ if (is_valid_pos(pos[p]) && pos[p].row == piece.row + direction && board[pos[p].col][pos[p].row] == EMPTY) add_move(piece, &pos[p], 1); else if (is_valid_pos(pos[p]) && is_opposite(player, board[pos[p].col][pos[p].row])){ char tmp = board[pos[p].row][pos[p].col]; board[pos[p].row][pos[p].col] = EMPTY; Pos new_piece = get_next_diag(piece, pos[p]); if (is_valid_pos(new_piece) && board[new_piece.row][new_piece.col] == EMPTY){ found_ahead = get_capture_moves(piece, new_piece, board, player, 1, &new_piece); if (found_ahead == 0) add_move(piece, &new_piece, 1); } board[pos[p].row][pos[p].col] = tmp; } } }
void set_cell(board_t* board, player_t player, pos_t pos) { assert(NULL != board); assert(is_valid_pos(pos)); assert(is_valid_board(board)); // make sure the given cell is empty assert(EMPTY == get_cell(board, pos)); board->b[player][pos.y] = set(board->b[player][pos.y], trans_x(pos.x)); }
void get_pawn_moves(char board[BOARD_SIZE][BOARD_SIZE], COLOR player, Pos piece){ int direction = board[piece.col][piece.row] == BLACK_P ? -1 : 1; int pawn_row = board[piece.col][piece.row] == BLACK_P ? 6 : 1; Pos dest; dest.col = piece.col; dest.row = piece.row + direction; if (is_valid_pos(dest)){ if (board[dest.col][dest.row] == EMPTY){ add_move(piece, dest, 0); if (is_EOB(dest, player)) for (int i = 1; i < 5; i++) add_move(piece, dest, get_piece_by_type(i, player)); } } if (piece.row == pawn_row){ dest.row = piece.row + (2 * direction); if (is_valid_pos(dest)){ if (board[dest.col][dest.row] == EMPTY && board[piece.col][piece.row + direction] == EMPTY) add_move(piece, dest, 0); } } dest.col = piece.col + 1; dest.row = piece.row + direction; if (is_valid_pos(dest)){ if (is_opposite(player, board[dest.col][dest.row])){ add_move(piece, dest, 0); if (is_EOB(dest, player)) for (int i = 1; i < 5; i++) add_move(piece, dest, get_piece_by_type(i, player)); } } dest.col = piece.col - 1; if (is_valid_pos(dest)){ if (is_opposite(player, board[dest.col][dest.row])){ add_move(piece, dest, 0); if (is_EOB(dest, player)) for (int i = 1; i < 5; i++) add_move(piece, dest, get_piece_by_type(i, player)); } } }
void set_cell_state(board_t* board, pos_t pos, cell_t new_state) { assert(NULL != board); assert(is_valid_board(board)); assert(is_valid_pos(pos)); /* // this assertion is tentative, it may prove too strict */ /* // it relies on the caller checking the state of this cell */ /* // before trying to change it */ /* const cell_t old_state = get_cell(board, pos); */ /* assert(new_state != old_state); */ row* white_col = &board->b[W][pos.y]; row* black_col = &board->b[B][pos.y]; switch (new_state) { case WHITE: *black_col = unset(*black_col, trans_x(pos.x)); *white_col = set(*white_col, trans_x(pos.x)); break; case BLACK: *white_col = unset(*white_col, trans_x(pos.x)); *black_col = set(*black_col, trans_x(pos.x)); break; case EMPTY: // deactivate the bit representing the cell at _pos_ // we apply the macro to both columns because we don't // know to which player it belongs *white_col = unset(*white_col, trans_x(pos.x)); *black_col = unset(*black_col, trans_x(pos.x)); } // make sure we didn't corrupt the board in the process of // updating the cell assert(is_valid_board(board)); }
void get_moves_by_piece(char board[BOARD_SIZE][BOARD_SIZE], COLOR player, Pos piece){ Pos* tmp_dests; switch (board[piece.col][piece.row]){ case WHITE_B: case BLACK_B: get_bishop_moves(board, player, piece); return; case WHITE_R: case BLACK_R: get_rook_moves(board, player, piece); return; case WHITE_Q: case BLACK_Q: get_bishop_moves(board, player, piece); get_rook_moves(board, player, piece); return; case BLACK_P: case WHITE_P: get_pawn_moves(board, player, piece); return; case WHITE_K: case BLACK_K: tmp_dests = (Pos[8]) { { piece.col - 1, piece.row - 1 }, { piece.col - 1, piece.row }, { piece.col - 1, piece.row + 1 }, { piece.col + 1, piece.row - 1 }, { piece.col + 1, piece.row }, { piece.col + 1, piece.row + 1 }, { piece.col, piece.row - 1 }, { piece.col, piece.row + 1 } }; break; case WHITE_N: case BLACK_N: tmp_dests = (Pos[8]) { { piece.col - 2, piece.row - 1 }, { piece.col - 2, piece.row + 1 }, { piece.col + 2, piece.row - 1 }, { piece.col + 2, piece.row + 1 }, { piece.col - 1, piece.row - 2 }, { piece.col + 1, piece.row - 2 }, { piece.col - 1, piece.row + 2 }, { piece.col + 1, piece.row + 2 }}; break; default: return; } for (int i = 0; i < 8; i++){ if (is_valid_pos(tmp_dests[i])){ if (board[tmp_dests[i].col][tmp_dests[i].row] == EMPTY || is_opposite(player, board[tmp_dests[i].col][tmp_dests[i].row])){ add_move(piece, tmp_dests[i], 0); } } } return; }
int n_neighbors(const board_t* board, pos_t pos, player_t player) { assert(NULL != board); assert(is_valid_pos(pos)); // TODO figure out the best way to introduce an offset const cell_t cell_content = get_cell(board, pos); // make sure the cell's occupied assert(W == player || B == player); // bit pattern to find the cell's active neighbors const row pattern = (1 | 2 | 4) << pos.x; // begin by -1 to prevent this cell from being counted // FIXME converting a cell_t to a player_t might be a bad idea, no? int n_neighbors = player == (player_t) cell_content ? -1 : 0; // count the neighbors in the three rows closest to the cell for (size_t i = max(0, pos.y - 1); i <= min(ROWS - 1, pos.y + 1); i++) { row neighbors = pattern & board->b[player][i]; // count 1 bits (that is, neighbors) for (; neighbors; neighbors >>= 1) { n_neighbors += neighbors & 1; } } assert(n_neighbors >= 0); return n_neighbors; }
void draw_multi_rooms (void) { int x, y; mr_map_rooms (); if (anim_cycle == 0) { generate_wall_colors_for_room (0, room0_wall_color); } if (em == PALACE && vm == VGA && (has_mr_view_changed () || em != mr.last.em || vm != mr.last.vm)) generate_wall_colors (); if (has_mr_view_changed ()) { generate_stars (); generate_mirrors_reflex (); } if (mouse_pos.room != mr.last.mouse_pos.room || mouse_pos.floor != mr.last.mouse_pos.floor || mouse_pos.place != mr.last.mouse_pos.place) { if (is_valid_pos (&mouse_pos)) update_cache_pos (&mouse_pos, em, vm); if (is_valid_pos (&mr.last.mouse_pos)) update_cache_pos (&mr.last.mouse_pos, em, vm); } if (anim_cycle == 0 || em != mr.last.em || vm != mr.last.vm || hgc != mr.last.hgc || hue != mr.last.hue) { update_room0_cache (em, vm); } if (anim_cycle == 0 || has_mr_view_changed () || em != mr.last.em || vm != mr.last.vm || hgc != mr.last.hgc || hue != mr.last.hue || level.number != mr.last.level) { update_cache (em, vm); } size_t i; for (i = 0; i < changed_pos_nmemb; i++) { /* printf ("%i,%i,%i\n", changed_pos[i].room, changed_pos[i].floor, changed_pos[i].place); */ update_cache_pos (&changed_pos[i], em, vm); } destroy_array ((void **) &changed_pos, &changed_pos_nmemb); clear_bitmap (screen, BLACK); for (y = mr.h - 1; y >= 0; y--) for (x = 0; x < mr.w; x++) { if (! mr.cell[x][y].room) continue; mr.dx = x; mr.dy = y; draw_animated_background (mr.cell[x][y].screen, mr.cell[x][y].room); } if (! no_room_drawing) draw_bitmap (cache, screen, 0, 0, 0); for (y = mr.h - 1; y >= 0; y--) for (x = 0; x < mr.w; x++) { if (! mr.cell[x][y].room) continue; mr.dx = x; mr.dy = y; draw_animated_foreground (mr.cell[x][y].screen, mr.cell[x][y].room); } if (mr.select_cycles > 0) { al_hold_bitmap_drawing (false); int x0 = ORIGINAL_WIDTH * mr.x; int y0 = ROOM_HEIGHT * mr.y + 3; int x1 = x0 + ORIGINAL_WIDTH; int y1 = y0 + ROOM_HEIGHT; draw_rectangle (screen, x0, y0, x1, y1, RED, 1); mr.select_cycles--; } mr.dx = mr.dy = -1; mr_update_last_settings (); }
// manages the users turn, game state user input loop int user_turn(char board[BOARD_SIZE][BOARD_SIZE], COLOR color){ get_all_moves(board, color); if (moves_head == NULL) return WIN_POS; char *word1; char *command = NULL; Move* new_move = NULL; int ret_val; while (1){ printf(ENTER_YOUR_MOVE); if (new_move != NULL) clear_old_moves(new_move); new_move = malloc(sizeof(Move)); new_move->dest = malloc(sizeof(Pos) * 2 * BOARD_SIZE); new_move->next = NULL; if (command != NULL) free(command); command = input2str(stdin); word1 = strtok(command, " "); if (strcmp(word1, "quit") == 0){ ret_val = QUIT; break; } else if (strcmp(word1, "get_moves") == 0){ print_moves(moves_head); continue; } else if (strcmp(word1, "move") == 0){ char * piece_coor1 = strtok(NULL, " <,>"); char * piece_coor2 = strtok(NULL, " <,>"); new_move->piece.col = piece_coor1[0] - 'a'; new_move->piece.row = atoi(piece_coor2) - 1; if (!is_valid_pos(new_move->piece)){ printf(WRONG_POSITION); continue; } int i = 0; char * dest_coor1 = strtok(NULL, " <,>to"); char * dest_coor2 = strtok(NULL, " <,>to"); while (dest_coor1 != NULL){ new_move->dest[i].col = dest_coor1[0] - 'a'; new_move->dest[i].row = atoi(dest_coor2) - 1; if (!is_valid_pos(new_move->dest[i])){ i = -1; break; } i++; dest_coor1 = strtok(NULL, " <,>[]"); if (dest_coor1 != NULL) dest_coor2 = strtok(NULL, " <,>[]"); } if (i == -1){ printf(WRONG_POSITION); continue; } if (!is_valid_piece(board, new_move, color)){ printf(NO_DISC); continue; } new_move->dest = realloc(new_move->dest, sizeof(Pos) * i); new_move->captures = i; Move * move2do = is_valid_move(moves_head, new_move); if (move2do == NULL){ printf(ILLEGAL_MOVE); continue; } else{ exc_move(board, move2do); print_board(board); ret_val = GAME_ON; break; } } else printf(ILLEGAL_COMMAND); } free(command); clear_old_moves(new_move); clear_old_moves(moves_head); return ret_val; }
void draw_multi_rooms (void) { int x, y; mr_set_origin (mr.room, mr.x, mr.y); bool mr_full_update = has_mr_view_changed () || mr.full_update; if (mr_full_update) { mr_busy (); force_full_redraw = true; } if (anim_cycle == 0) { generate_wall_colors_for_room (0, room0_wall_color); } if (em == PALACE && vm == VGA && (mr_full_update || em != mr.last.em || vm != mr.last.vm)) generate_wall_colors (); if (mouse_pos.room != mr.last.mouse_pos.room || mouse_pos.floor != mr.last.mouse_pos.floor || mouse_pos.place != mr.last.mouse_pos.place) { if (is_valid_pos (&mouse_pos)) register_changed_pos (&mouse_pos); if (is_valid_pos (&mr.last.mouse_pos)) register_changed_pos (&mr.last.mouse_pos); } if (anim_cycle == 0 || em != mr.last.em || vm != mr.last.vm || hgc != mr.last.hgc || hue != mr.last.hue) { update_room0_cache (em, vm); force_full_redraw = true; } size_t i; if (anim_cycle == 0 || mr_full_update || em != mr.last.em || vm != mr.last.vm || hgc != mr.last.hgc || hue != mr.last.hue || global_level.n != mr.last.level) { update_cache (em, vm); } else { bool depedv = ((em == DUNGEON && vm == VGA) || (em == DUNGEON && vm == EGA) || (em == PALACE && vm == EGA)); /* optmize changed pos list */ optimize_changed_pos (); /* update cache pos */ for (i = 0; i < changed_pos_nmemb; i++) { update_cache_pos (&changed_pos[i], em, vm); struct pos pl; prel (&changed_pos[i], &pl, +0, -1); if (depedv && fake (&pl) == WALL) update_cache_pos (&pl, em, vm); } /* update cache room */ for (i = 0; i < changed_room_nmemb; i++) update_cache_room (changed_room[i], em, vm); /* kept together so update_cache_pos and update_cache_room can access each other's arrays */ destroy_array ((void **) &changed_pos, &changed_pos_nmemb); destroy_array ((void **) &changed_room, &changed_room_nmemb); } for (y = mr.h - 1; y >= 0; y--) for (x = 0; x < mr.w; x++) { clear_bitmap (mr.cell[x][y].screen, (mr.flicker > 0 && mr.flicker % 2) ? mr.color : BLACK); if (! mr.cell[x][y].room) continue; mr.dx = x; mr.dy = y; draw_animated_background (mr.cell[x][y].screen, mr.cell[x][y].room); } if (mr.flicker > 0) mr.flicker--; struct mr_room_list l; mr_get_room_list (&l); int xm, ym; if (! no_room_drawing) for (i = 0; i < l.nmemb; i++) { mr_coord (l.room[i], -1, &xm, &ym); for (y = mr.h - 1; y >= 0; y--) for (x = 0; x < mr.w; x++) if (mr.cell[x][y].room == l.room[i]) draw_bitmap (mr.cell[xm][ym].cache, mr.cell[x][y].screen, 0, 0, 0); } mr_destroy_room_list (&l); for (y = mr.h - 1; y >= 0; y--) for (x = 0; x < mr.w; x++) { if (! mr.cell[x][y].room) continue; mr.dx = x; mr.dy = y; draw_animated_foreground (mr.cell[x][y].screen, mr.cell[x][y].room); } mr_update_last_settings (); }
int is_pos_threatened(Pos pos, char board[BOARD_SIZE][BOARD_SIZE], COLOR player){ Pos curr; int blocked[4] = { 0 }; char* pieces; char bpieces[6] = { BLACK_P, BLACK_B, BLACK_N, BLACK_R, BLACK_Q, BLACK_K }; char wpieces[6] = { WHITE_P, WHITE_B, WHITE_N, WHITE_R, WHITE_Q, WHITE_K }; pieces = (player == WHITE) ? bpieces : wpieces; // check pawns int dir = player == WHITE ? 1 : -1; curr.row = pos.row + dir; curr.col = pos.col - 1; if (is_valid_pos(curr)){ if (board[curr.col][curr.row] == pieces[0]) return 1; } curr.col = pos.col + 1; if (is_valid_pos(curr)){ if (board[curr.col][curr.row] == pieces[0]) return 1; } // check bishops + queen for (int i = 1; i < BOARD_SIZE; i++){ curr.col = pos.col - i, curr.row = pos.row - i; if (is_valid_pos(curr) && !blocked[0]){ blocked[0] = (board[curr.col][curr.row] != EMPTY) ? 1 : 0; if (board[curr.col][curr.row] == pieces[1] || board[curr.col][curr.row] == pieces[4]) return 1; } curr.col = pos.col + i; if (is_valid_pos(curr) && !blocked[1]){ blocked[1] = (board[curr.col][curr.row] != EMPTY) ? 1 : 0; if (board[curr.col][curr.row] == pieces[1] || board[curr.col][curr.row] == pieces[4]) return 1; } curr.row = pos.row + i; if (is_valid_pos(curr) && !blocked[2]){ blocked[2] = (board[curr.col][curr.row] != EMPTY) ? 1 : 0; if (board[curr.col][curr.row] == pieces[1] || board[curr.col][curr.row] == pieces[4]) return 1; } curr.col = pos.col - i; if (is_valid_pos(curr) && !blocked[3]){ blocked[3] = (board[curr.col][curr.row] != EMPTY) ? 1 : 0; if (board[curr.col][curr.row] == pieces[1] || board[curr.col][curr.row] == pieces[4]) return 1; } } // check knights Pos dests[8] = {{ pos.col - 2, pos.row - 1 }, { pos.col - 2, pos.row + 1 }, { pos.col + 2, pos.row - 1 }, { pos.col + 2, pos.row + 1 }, { pos.col - 1, pos.row - 2 }, { pos.col + 1, pos.row - 2 }, { pos.col - 1, pos.row + 2 }, { pos.col + 1, pos.row + 2 }}; for (int i = 0; i < 8; i++){ if (is_valid_pos(dests[i])){ if (board[dests[i].col][dests[i].row] == pieces[2]) return 1; } } // check rooks + queen for (int j = 0; j < 4; j++) blocked[j] = 0; for (int i = 1; i < BOARD_SIZE; i++){ curr.col = pos.col - i; curr.row = pos.row; if (is_valid_pos(curr) && !blocked[0]){ blocked[0] = (board[curr.col][curr.row] != EMPTY) ? 1 : 0; if (board[curr.col][curr.row] == pieces[3] || board[curr.col][curr.row] == pieces[4]) return 1; } curr.col = pos.col + i; if (is_valid_pos(curr) && !blocked[1]){ blocked[1] = (board[curr.col][curr.row] != EMPTY) ? 1 : 0; if (board[curr.col][curr.row] == pieces[3] || board[curr.col][curr.row] == pieces[4]) return 1; } curr.col = pos.col, curr.row = pos.row - i; if (is_valid_pos(curr) && !blocked[2]){ blocked[2] = (board[curr.col][curr.row] != EMPTY) ? 1 : 0; if (board[curr.col][curr.row] == pieces[3] || board[curr.col][curr.row] == pieces[4]) return 1; } curr.row = pos.row + i; if (is_valid_pos(curr) && !blocked[3]){ blocked[3] = (board[curr.col][curr.row] != EMPTY) ? 1 : 0; if (board[curr.col][curr.row] == pieces[3] || board[curr.col][curr.row] == pieces[4]) return 1; } } // check king Pos kdests[8] = { { pos.col - 1, pos.row - 1 }, { pos.col - 1, pos.row }, { pos.col - 1, pos.row + 1 }, { pos.col + 1, pos.row - 1 }, { pos.col + 1, pos.row }, { pos.col + 1, pos.row + 1 }, { pos.col, pos.row - 1 }, { pos.col, pos.row + 1 } }; for (int i = 0; i < 8; i++){ if (is_valid_pos(kdests[i])){ if (board[kdests[i].col][kdests[i].row] == pieces[5]) return 1; } } // no threat return 0; }
// Helper func - checks if a piece belongs to the player int is_valid_piece(char board[BOARD_SIZE][BOARD_SIZE], Move * move, COLOR color){ if (is_valid_pos(move->piece) && board[move->piece.col][move->piece.row] != EMPTY) return !is_opposite(color, board[move->piece.col][move->piece.row]); return 0; }
void fight_ai (struct anim *k) { /* non-fightable characters don't fight */ if (! is_fightable_anim (k)) return; /* controllables and non-fighters doesn't need AI to fight */ if (k->controllable || ! k->fight) return; /* if forgetting about an enemy, no need to fight */ if (k->enemy_refraction > 0) return; /* without an enemy or awareness, no need to fight */ if (k->enemy_id == -1) { if (is_in_fight_mode (k)) leave_fight_mode (k); return; } /* first thing, enter in fight mode */ if (! is_in_fight_mode (k)) { enter_fight_mode (k); return; } /* who's the enemy? */ struct anim *ke = get_anim_by_id (k->enemy_id); /* what's the facing opposite direction? */ enum dir odir = (k->f.dir == LEFT) ? RIGHT : LEFT; /* get positions */ struct pos p, pe; survey (_m, pos, &k->f, NULL, &p, NULL); survey ((k->f.dir != ke->f.dir) ? _m : _mba, pos, &ke->f, NULL, &pe, NULL); pos2room (&pe, p.room, &pe); /* remember the place the enemy was last seen */ if (pe.room == p.room && pe.floor == p.floor) k->enemy_pos = pe; else if (pe.floor > p.floor && is_valid_pos (&k->enemy_pos) && ! is_strictly_traversable (&k->enemy_pos)) k->enemy_pos.place = pe.place; if (is_valid_pos (&k->enemy_pos) && is_strictly_traversable (&k->enemy_pos)) { struct pos pp; int d = (p.place < k->enemy_pos.place) ? -1 : +1; while (is_strictly_traversable (prel (&k->enemy_pos, &pp, +0, d))) k->enemy_pos = pp; } /* prevent enemy from passing through */ if (ke->type == KID && is_in_range (k, ke, ATTACK_RANGE) && ! is_in_fight_mode (ke) && ! ke->immortal && ! (is_kid_climb (&ke->f) && ke->i <= 7) && ke->f.dir != k->f.dir && ke->current_lives > 0 && ke->has_sword && ! is_kid_fall (&ke->f) && ! is_kid_hang (&ke->f) && ! is_kid_jump_air (&ke->f) && ! is_kid_run_jump_air (&ke->f) && is_safe_to_attack (ke)) { place_on_the_ground (&ke->f, &ke->f.c); kid_take_sword (ke); ke->auto_taken_sword = true; } /* prevent enemy from hiding near */ if (ke->type == KID && is_in_range (k, ke, INVERSION_RANGE) && ! is_in_fight_mode (ke) && ke->current_lives > 0) { if (is_safe_to_walkb (k)) fight_walkb (k); else if (is_safe_to_turn (k)) fight_turn (k); return; } /* if the enemy is on the back, turn */ if (is_on_back (k, ke) && is_anim_seeing (k, ke, odir) && p.floor == pe.floor && ! is_in_range (k, ke, INVERSION_RANGE)) { if (is_safe_to_turn (k)) fight_turn (k); else if (is_safe_to_walkb (k)) fight_walkb (k); return; } /* if too near to a wall, back off to have room for an attack */ if (fight_crel (k, +0, +1) == WALL && is_safe_to_walkb (k)) { fight_walkb (k); return; } /* /\* if the enemy can be followed in the opposite direction, turn *\/ */ /* if (! is_safe_to_follow (k, ke, k->f.dir) */ /* && is_safe_to_follow (k, ke, odir)) { */ /* fight_turn (k); */ /* return; */ /* } */ /* if the enemy is trying to bypass, attack him */ if (! is_in_fight_mode (ke) && ! ke->has_sword && ! is_kid_stairs (&ke->f) && ke->f.dir != k->f.dir && ke->current_lives > 0 && ! is_on_back (k, ke) && ((is_kid_run (&ke->f) && is_in_range (k, ke, 3 * PLACE_WIDTH - 4)) || (is_kid_run_jump (&ke->f) && is_in_range (k, ke, 4 * PLACE_WIDTH - 4)) || (is_kid_jump_air (&ke->f) && ke->i < 9 && is_in_range (k, ke, 4 * PLACE_WIDTH)))) { if (is_safe_to_attack (k)) fight_attack (k); else if (is_safe_to_walkb (k)) fight_walkb (k); return; } /* stays at least in the fight range. Advance, unless the enemy is not running towards you */ if (! is_in_range (k, ke, FIGHT_RANGE + 10) && ! is_kid_stairs (&ke->f) && (ke->f.dir == k->f.dir || p.room != pe.room || p.floor != pe.floor || ! (is_kid_run (&ke->f) || is_kid_run_jump (&ke->f) || is_kid_jump (&ke->f))) && is_safe_to_follow (k, ke, k->f.dir)) { fight_walkf (k); return; } /* if the enemy is not targeting you, do nothing more */ if (ke->enemy_id != -1 && ke->enemy_id != k->id) return; /* in fight range, if the enemy is not attacking, go towards attack range (with probability, unless the enemy is not in fight mode, then go immediately) */ if (is_in_range (k, ke, FIGHT_RANGE + 10) && ! is_in_range (k, ke, ATTACK_RANGE) && ! is_kid_stairs (&ke->f) && is_safe_to_follow (k, ke, k->f.dir) && (prandom (99) <= k->skill.advance_prob || ! is_in_fight_mode (ke)) && ! is_attacking (ke) && (! is_in_fight_mode (ke) || is_walking (ke) || ke->i >= 6 + prandom (24))) { fight_walkf (k); return; } /* in attack range, if being attacked, defend yourself (with probability) and counter attack (with probability handled elsewhere) */ if (is_in_range (k, ke, ATTACK_RANGE + 16) && ! is_on_back (k, ke) && (is_attacking (ke) && ke->i == 0) && (prandom (99) <= k->skill.defense_prob || k->refraction > 0) && ke->current_lives > 0) { fight_defense (k); fight_attack (k); return; } /* if attacking, counter defend (with probability handled elsewhere) */ if (is_in_range (k, ke, ATTACK_RANGE + 16) && is_attacking (k)) { fight_defense (k); fight_attack (k); return; } /* in attack range, if not being attacked, attack (with probability, unless the enemy is not in fight mode, then attack immediately) */ if (is_in_range (k, ke, ATTACK_RANGE) && ! is_attacking (ke) && ! is_on_back (k, ke) && ! is_kid_stairs (&ke->f) && ! ((is_kid_climb (&ke->f) || is_kid_successfully_climbing (&ke->f)) && ke->i >= 1) && ke->current_lives > 0 && (prandom (99) <= k->skill.attack_prob || ! is_in_fight_mode (ke))) { if (is_safe_to_attack (k)) fight_attack (k); else if (is_safe_to_walkb (k)) fight_walkb (k); return; } /* in hit range, back off (with probability) */ if (is_in_range (k, ke, HIT_RANGE - 10) && is_safe_to_walkb (k) && ! k->refraction && ! is_walkingb (ke) && prandom (99) <= k->skill.return_prob) { fight_walkb (k); return; } }
void draw_multi_rooms (void) { int x, y; mr_set_origin (mr.room, mr.x, mr.y); bool mr_view_changed = has_mr_view_changed (); if (mr_view_changed) force_full_redraw = true; if (anim_cycle == 0) { generate_wall_colors_for_room (0, room0_wall_color); } if (em == PALACE && vm == VGA && (mr_view_changed || em != mr.last.em || vm != mr.last.vm)) generate_wall_colors (); if (mr_view_changed) generate_stars (); if (mouse_pos.room != mr.last.mouse_pos.room || mouse_pos.floor != mr.last.mouse_pos.floor || mouse_pos.place != mr.last.mouse_pos.place) { if (is_valid_pos (&mouse_pos)) update_cache_pos (&mouse_pos, CHPOS_MOUSE_SELECT, em, vm); if (is_valid_pos (&mr.last.mouse_pos)) update_cache_pos (&mr.last.mouse_pos, CHPOS_MOUSE_DESELECT, em, vm); } if (anim_cycle == 0 || em != mr.last.em || vm != mr.last.vm || hgc != mr.last.hgc || hue != mr.last.hue) { update_room0_cache (em, vm); force_full_redraw = true; } if (anim_cycle == 0 || mr_view_changed || em != mr.last.em || vm != mr.last.vm || hgc != mr.last.hgc || hue != mr.last.hue || global_level.number != mr.last.level) { update_cache (em, vm); } size_t i; for (i = 0; i < changed_pos_nmemb; i++) update_cache_pos (&changed_pos[i].p, changed_pos[i].reason, em, vm); destroy_array ((void **) &changed_pos, &changed_pos_nmemb); for (i = 0; i < changed_room_nmemb; i++) update_cache_room (changed_room[i], em, vm); destroy_array ((void **) &changed_room, &changed_room_nmemb); for (y = mr.h - 1; y >= 0; y--) for (x = 0; x < mr.w; x++) { clear_bitmap (mr.cell[x][y].screen, (mr.flicker > 0 && mr.flicker % 2) ? mr.color : BLACK); if (! mr.cell[x][y].room) continue; mr.dx = x; mr.dy = y; draw_animated_background (mr.cell[x][y].screen, mr.cell[x][y].room); } if (mr.flicker > 0) mr.flicker--; struct mr_room_list l; mr_get_room_list (&l); int xm, ym; if (! no_room_drawing) for (i = 0; i < l.nmemb; i++) { mr_coord (l.room[i], -1, &xm, &ym); for (y = mr.h - 1; y >= 0; y--) for (x = 0; x < mr.w; x++) if (mr.cell[x][y].room == l.room[i]) draw_bitmap (mr.cell[xm][ym].cache, mr.cell[x][y].screen, 0, 0, 0); } mr_destroy_room_list (&l); /* if (! no_room_drawing) */ /* for (y = mr.h - 1; y >= 0; y--) */ /* for (x = 0; x < mr.w; x++) */ /* if (mr.cell[x][y].room) */ /* draw_bitmap (mr.cell[x][y].cache, mr.cell[x][y].screen, 0, 0, 0); */ for (y = mr.h - 1; y >= 0; y--) for (x = 0; x < mr.w; x++) { if (! mr.cell[x][y].room) continue; mr.dx = x; mr.dy = y; draw_animated_foreground (mr.cell[x][y].screen, mr.cell[x][y].room); } /* if (mr.select_cycles > 0) { */ /* int t = max_int (mr.w, mr.h); */ /* draw_rectangle (mr.cell[mr.x][mr.y].screen, 0, 3, */ /* ORIGINAL_WIDTH - t, */ /* 3 + ROOM_HEIGHT - t, RED, t); */ /* mr.select_cycles--; */ /* } */ mr_update_last_settings (); }
bool is_safe_to_follow (struct anim *k0, struct anim *k1, enum dir dir) { /* not aware of enemy position */ if (! is_valid_pos (&k0->enemy_pos)) return false; struct pos p0, p, p1, pke, pk; survey (_m, pos, &k0->f, NULL, &p0, NULL); survey ((k0->f.dir == LEFT) ? _mr : _ml, pos, &k1->f, NULL, &p1, NULL); pos2room (&p1, p0.room, &p1); /* not reachable, to start with */ if (p0.room != p1.room) return false; if (p0.floor > p1.floor) return false; /* the character went down after the enemy */ if (p0.floor != k0->enemy_pos.floor) { /* enum dir odir = (dir == LEFT) ? RIGHT : LEFT; */ /* if (is_on_back (k0, k1) && is_seeing (k0, k1, odir) */ /* && p0.floor == p1.floor) return true; */ if (is_anim_seeing (k0, k1, LEFT) || is_anim_seeing (k0, k1, RIGHT)) return true; return false; } /* if falling the chasing is inevitable (necessary to prevent leave_fight_logic from forgeting enemy based on the facing direction of the is_in_range check) */ if (is_anim_fall (&k0->f)) return true; if (dir == LEFT) { if (! is_safe_at_left (&p0)) return false; if (! is_safe_at_right (&k0->enemy_pos, &k0->f)) return false; if (peqr (&k0->enemy_pos, &p0, +0, -1)) return true; prel (&p0, &pk, +0, -1); prel (&k0->enemy_pos, &pke, +0, +1); if (is_collidable_at_right (&pk, &k0->f)) return false; } else { if (! is_safe_at_right (&p0, &k0->f)) return false; if (! is_safe_at_left (&k0->enemy_pos)) return false; if (peqr (&k0->enemy_pos, &p0, +0, +1)) return true; prel (&p0, &pk, +0, +1); prel (&k0->enemy_pos, &pke, +0, -1); if (is_collidable_at_right (&p0, &k0->f)) return false; } /* enemy went down */ if (is_traversable (&k0->enemy_pos)) { prel (&k0->enemy_pos, &pke, +1, +0); if (is_traversable (&pke) || fg (&pke) == SPIKES_FLOOR) return false; int d = (dir == LEFT) ? -1 : +1; if (peq (&pk, &k0->enemy_pos)) return true; prel (&k0->enemy_pos, &pke, +0, -1 * d); } else if (peq (&p0, &k0->enemy_pos) && ! (is_anim_seeing (k0, k1, LEFT) || is_anim_seeing (k0, k1, RIGHT))) return false; first_confg (&pk, &pke, dangerous_cs, &p); if (is_valid_pos (&p)) return false; first_confg (&pk, &pke, door_cs, &p); if (! is_valid_pos (&p)) return true; else return door_at_pos (&p)->action == OPEN_DOOR || ! is_collidable_at_right (&p, &k0->f); }