#include "field.h" #include "ghosts.h" #include "pac.h" #include "queue.h" #include #include #include #include enum { timeout_duration = 0, sleep_duration = 190000, key_escape = 27, count_get_out_moves = 6, chase_move_limit = 70, scatter_move_limit = 35, frightened_move_limit = 30, phase_limit = 4, prison_limit = 30 }; struct mode_type { enum behavior_mode current_mode; int chase_count; int scatter_count; int frightened_count; int phase_number; int reverse_direction; }; struct game_params_type { int exit; int pause; }; static void initialize_params(struct game_params_type *basic_params) { srand(time(NULL)); initscr(); start_color(); cbreak(); noecho(); curs_set(0); keypad(stdscr, 1); timeout(timeout_duration); start_color(); basic_params->exit = 0; basic_params->pause = 0; } static void initialize_ghosts(struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) { initialize_ghost(red_ghost, red); initialize_ghost(pink_ghost, pink); initialize_ghost(blue_ghost, blue); initialize_ghost(orange_ghost, orange); } static void initialize_modes(struct mode_type *mode_params, int *get_out_stage) { mode_params->current_mode = scatter; mode_params->chase_count = 0; mode_params->scatter_count = 0; mode_params->frightened_count = 0; mode_params->phase_number = 0; mode_params->reverse_direction = 0; *get_out_stage = count_get_out_moves; } static int is_up_move_blocked(const struct ghost_type *ghost, enum intersection_type intersection) { return intersection == yellow_block && (ghost->direction == left || ghost->direction == right); } static void pathfinder_stage(game_space field, struct mode_type *mode_params, const struct pacman *pac, struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) { void (*search_method)(game_space, struct ghost_type*, struct coordinates); enum intersection_type intersection; int color_priority; struct ghost_type *current_ghost; struct coordinates new_target_point; for(color_priority = 0; color_priority <= orange; ++color_priority) { switch(color_priority) { case red: if(red_ghost->prison_params.active) continue; current_ghost = red_ghost; new_target_point = mode_params->current_mode == scatter ? current_ghost->home_position : pac->position; search_method = mode_params->current_mode == scatter ? compute_distance_between_points : breadth_first_search; break; case pink: if(pink_ghost->prison_params.active) continue; current_ghost = pink_ghost; new_target_point = mode_params->current_mode == scatter ? current_ghost->home_position : identify_target_in_front(*pac, pink_shift); search_method = compute_distance_between_points; break; case blue: if(blue_ghost->prison_params.active) continue; current_ghost = blue_ghost; new_target_point = mode_params->current_mode == scatter ? current_ghost->home_position : identify_blue_target(*pac, red_ghost); search_method = compute_distance_between_points; break; case orange: if(orange_ghost->prison_params.active) continue; current_ghost = orange_ghost; new_target_point = mode_params->current_mode == scatter ? current_ghost->home_position : pac->position; search_method = mode_params->current_mode == scatter ? compute_distance_between_points : breadth_first_search; } intersection = get_intersection(field, current_ghost); if(is_up_move_blocked(current_ghost, intersection)) continue; if(intersection != direct_path) redirect(field, intersection, current_ghost, new_target_point, search_method); } } static void random_pathfinder_stage(game_space field, struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) { enum intersection_type intersection; int color_priority; struct ghost_type *current_ghost; for(color_priority = 0; color_priority <= orange; ++color_priority) { switch(color_priority) { case red: if(red_ghost->prison_params.active) continue; current_ghost = red_ghost; break; case pink: if(pink_ghost->prison_params.active) continue; current_ghost = pink_ghost; break; case blue: if(blue_ghost->prison_params.active) continue; current_ghost = blue_ghost; break; case orange: if(orange_ghost->prison_params.active) continue; current_ghost = orange_ghost; break; } intersection = get_intersection(field, current_ghost); if(intersection != direct_path) random_redirect(field, current_ghost); } } static void change_mode(struct mode_type *mode_params) { if(!(mode_params->current_mode == frightened) && mode_params->phase_number == phase_limit) return; switch(mode_params->current_mode) { case chase: if(mode_params->chase_count > chase_move_limit) { mode_params->current_mode = scatter; mode_params->chase_count = 0; ++mode_params->phase_number; if(mode_params->phase_number == phase_limit) mode_params->current_mode = chase; if(mode_params->phase_number != phase_limit) ++mode_params->reverse_direction; } break; case scatter: if(mode_params->scatter_count > scatter_move_limit) { mode_params->current_mode = chase; mode_params->scatter_count = 0; ++mode_params->reverse_direction; } break; case frightened: if(mode_params->frightened_count > frightened_move_limit) { mode_params->current_mode = mode_params->chase_count || mode_params->phase_number == phase_limit ? chase : scatter; mode_params->frightened_count = 0; ++mode_params->reverse_direction; } } } static void chase_mode(game_space field, struct mode_type *mode_params, const struct pacman *pac, struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) { pathfinder_stage(field, mode_params, pac, red_ghost, pink_ghost, blue_ghost, orange_ghost); if(mode_params->phase_number < phase_limit) { ++mode_params->chase_count; change_mode(mode_params); } } static void scatter_mode(game_space field, struct mode_type *mode_params, struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) { pathfinder_stage(field, mode_params, NULL, red_ghost, pink_ghost, blue_ghost, orange_ghost); if(mode_params->phase_number < phase_limit) { ++mode_params->scatter_count; change_mode(mode_params); } } static void frightened_mode(game_space field, struct mode_type *mode_params, struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) { random_pathfinder_stage(field, red_ghost, pink_ghost, blue_ghost, orange_ghost); ++mode_params->frightened_count; change_mode(mode_params); set_frightened_status(mode_params->current_mode == frightened ? 1 : 0, red_ghost, pink_ghost, blue_ghost, orange_ghost); } static int is_outside_prison(struct ghost_type ghost) { return ghost.prison_params.active && ghost.direction == up; } static int is_ghost_prisoner(struct ghost_type ghost) { return ghost.prison_params.active && ghost.direction == none; } static void prison_leaving_stage(game_space field, struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) { struct ghost_type *current_ghost; int color_priority; for(color_priority = 0; color_priority <= orange; ++color_priority) { switch(color_priority) { case red: current_ghost = red_ghost; break; case pink: current_ghost = pink_ghost; break; case blue: current_ghost = blue_ghost; break; case orange: current_ghost = orange_ghost; break; } if(is_ghost_prisoner(*current_ghost)) { ++current_ghost->prison_params.prison_counter; /* * liberation */ if(current_ghost->prison_params.prison_counter == prison_limit) { current_ghost->prison_params.prison_counter = 0; current_ghost->direction = up; } } else if(is_outside_prison(*current_ghost)) current_ghost->prison_params.active = current_ghost->position.y == liberation_y ? 0 : 1; } } static int is_castling(struct pacman pac, struct ghost_type ghost) { return ghost.capture_info.status && pac.position.x == ghost.capture_info.previous_ghost_position.x && pac.position.y == ghost.capture_info.previous_ghost_position.y && ghost.position.x == ghost.capture_info.previous_pac_position.x && ghost.position.y == ghost.capture_info.previous_pac_position.y; } static void catching_stage(game_space field, struct mode_type *mode_params, int *get_out_stage, struct pacman *pac, struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) { struct ghost_type *current_ghost; current_ghost = red_ghost; int color_priority; for(color_priority = 0; color_priority <= orange; ++color_priority) { switch(color_priority) { case red: if(is_pac_nearby(*pac, *red_ghost)) { set_capture_info(red_ghost, pac); continue; } current_ghost = red_ghost; break; case pink: if(is_pac_nearby(*pac, *pink_ghost)) { set_capture_info(pink_ghost, pac); continue; } current_ghost = pink_ghost; break; case blue: if(is_pac_nearby(*pac, *blue_ghost)) { set_capture_info(blue_ghost, pac); continue; } current_ghost = blue_ghost; break; case orange: if(is_pac_nearby(*pac, *orange_ghost)) { set_capture_info(orange_ghost, pac); continue; } current_ghost = orange_ghost; break; } if(is_equal_points(pac->position, current_ghost->position) || is_castling(*pac, *current_ghost)) { if(mode_params->current_mode == frightened) catch_ghost(field, current_ghost); else { catch_pac(pac); if(pac->lives) initialize_ghosts(red_ghost, pink_ghost, blue_ghost, orange_ghost); initialize_modes(mode_params, get_out_stage); usleep(sleep_duration); return; } } if(current_ghost->capture_info.status) current_ghost->capture_info.status = 0; } } static void show_defeat_screen() { move(17, 9); printw("GAME OVER"); refresh(); } static void restart_game(struct game_params_type *basic_params, game_space field, struct queue *eaten_coins, struct pacman *pac, struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) { initialize_params(basic_params); initialize_pac(pac); initialize_ghosts(red_ghost, pink_ghost, blue_ghost, orange_ghost); clear_field(field); field = get_new_field(); print_field(field); queue_clear(eaten_coins); queue_init(eaten_coins); } static void defeat_stage(struct game_params_type *basic_params) { int key; show_defeat_screen(); timeout(-1); while((key = getch()) != 'y' && key != 'n') {} if(key == 'y') basic_params->exit = 0; } int main() { game_space field = NULL; struct ghost_type red_ghost, pink_ghost, blue_ghost, orange_ghost; struct pacman pac; struct queue eaten_coins; struct mode_type mode_params; struct game_params_type basic_params; int key, get_out_stage; enum movement_direction stored_direction; stored_direction = none; initialize_params(&basic_params); field = get_new_field(); print_field(field); initialize_ghosts(&red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); initialize_pac(&pac); initialize_modes(&mode_params, &get_out_stage); queue_init(&eaten_coins); display_ghosts_on_field(&red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); display_character(pac.position.y, pac.position.x, pac_char); usleep(sleep_duration); while((key = getch()) != key_escape) { /* * pacman */ if(key != ERR) change_pac_direction(field, &pac, key, &stored_direction); else check_remaining_direction(field, &pac, &stored_direction); make_pac_move(field, &pac, &eaten_coins); if(pac.is_energizer_eaten) { mode_params.current_mode = frightened; mode_params.reverse_direction = 1; pac.is_energizer_eaten = 0; } /* * ghosts */ if(get_out_stage) pull_out_ghosts(&get_out_stage, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); else if(mode_params.reverse_direction) { reverse_all_ghosts(&red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); mode_params.reverse_direction = 0; } else if(mode_params.current_mode == chase) chase_mode(field, &mode_params, &pac, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); else if(mode_params.current_mode == scatter) scatter_mode(field, &mode_params, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); else if(mode_params.current_mode == frightened) frightened_mode(field, &mode_params, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); make_ghost_moves(field, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost, &eaten_coins); /* * displaying characters */ catching_stage(field, &mode_params, &get_out_stage, &pac, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); display_ghosts_on_field(&red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); display_character(pac.position.y, pac.position.x, pac_char); usleep(sleep_duration); prison_leaving_stage(field, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); #ifdef DEBUG move(0, 50); if(mode_params.current_mode == chase) printw("CHASE %d ", mode_params.chase_count); else if(mode_params.current_mode == scatter) printw("SCATTER %d ", mode_params.scatter_count); else if(mode_params.current_mode == frightened) printw("FRIGHTENED %d ", mode_params.frightened_count); move(1, 50); printw("LIVES: %d", pac.lives); refresh(); #endif if(!pac.lives) { defeat_stage(&basic_params); if(basic_params.exit) return 0; else restart_game(&basic_params, field, &eaten_coins, &pac, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); } } queue_clear(&eaten_coins); endwin(); return 0; }