#include "field.h" #include "ghosts.h" #include "pac.h" #include "queue.h" #include "color_palette.h" #include #include #include #include enum { timeout_duration = 0, sleep_duration = 120000, key_escape = 27, max_get_out_stage = 6, chase_move_limit = 70, scatter_move_limit = 35, frightened_move_limit = 50, phase_limit = 4, prison_limit = 30, max_score = 243 }; struct mode_type { enum behavior_mode current_mode; int chase_count; int scatter_count; int frightened_count; int phase_number; int reverse_direction; int get_out_stage; }; struct game_params_type { int exit; int pause; }; 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) { 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; mode_params->get_out_stage = max_get_out_stage; } static void initialize_params(game_space *field, struct queue *eaten_coins, struct mode_type *mode_params, struct pacman *pac, struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) { timeout(timeout_duration); *field = get_new_field(); print_field(*field); queue_init(eaten_coins); initialize_pac(pac); initialize_ghosts(red_ghost, pink_ghost, blue_ghost, orange_ghost); initialize_modes(mode_params); display_ghosts_on_field(red_ghost, pink_ghost, blue_ghost, orange_ghost); display_character(pac->position.y, pac->position.x, pac_char); } 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, 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 { current_ghost->reached_pacman = 1; catch_pac(pac); return; #if 0 initialize_ghosts(red_ghost, pink_ghost, blue_ghost, orange_ghost); return; #endif } } if(current_ghost->capture_info.status) current_ghost->capture_info.status = 0; } } static int ghost_caught_pacman(struct ghost_type red_ghost, struct ghost_type pink_ghost, struct ghost_type blue_ghost, struct ghost_type orange_ghost) { return red_ghost.reached_pacman || pink_ghost.reached_pacman || blue_ghost.reached_pacman || orange_ghost.reached_pacman; } static void final_stage(struct game_params_type *game_options, int win) { int key; reset_attr(); if(win) { move(17, 10); printw("YOU WIN"); } else { move(17, 9); printw("GAME OVER"); } move(14, 11); printw("RETRY?"); move(15, 12); printw("Y/N"); refresh(); timeout(-1); while((key = getch()) != 'y' && key != 'n') {} game_options->exit = (key == 'y') ? 0 : 1; } static void clear_field_and_queue(game_space field, struct queue *eaten_coins) { clear_field(field); queue_clear(eaten_coins); } 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 game_options; int key; enum movement_direction stored_direction; srand(time(NULL)); initscr(); start_color(); set_pairs(); cbreak(); noecho(); curs_set(0); keypad(stdscr, 1); stored_direction = none; game_options.exit = 0; game_options.pause = 0; initialize_params(&field, &eaten_coins, &mode_params, &pac, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); 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; /* if frightened mode is activated already */ mode_params.frightened_count = 0; } /* * ghosts */ if(mode_params.get_out_stage) pull_out_ghosts(&mode_params.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); /* * catching */ catching_stage(field, &mode_params, &pac, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); /* * displaying characters and score */ display_score(pac.score); display_ghosts_on_field(&red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); if(ghost_caught_pacman(red_ghost, pink_ghost, blue_ghost, orange_ghost)) { display_hit(pac.position, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); usleep(sleep_duration*5); } else 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); reset_attr(); 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); move(2, 50); printw("%d %d ", orange_ghost.position.x, orange_ghost.position.y); move(3, 50); printw("%d %d ", pac.position.x, pac.position.y); refresh(); #endif if(pac.lives < 0 || pac.score == max_score ) { #if 0 if(pac.lives < 0) display_ghosts_on_field(&red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); #endif final_stage(&game_options, pac.lives < 0 ? 0 : 1); if(game_options.exit) break; else { stored_direction = none; clear_field_and_queue(field, &eaten_coins); initialize_params(&field, &eaten_coins, &mode_params, &pac, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); usleep(sleep_duration); } continue; } if(ghost_caught_pacman(red_ghost, pink_ghost, blue_ghost, orange_ghost)) { erase_hit(pac.position); clear_ghost_positions(field, &eaten_coins, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); pac.position.x = pac_x; pac.position.y = pac_y; initialize_ghosts(&red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); initialize_modes(&mode_params); 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); } } clear_field_and_queue(field, &eaten_coins); endwin(); return 0; }