From 29afbdf8e26f741ac1d090f2e7704093253f17fc Mon Sep 17 00:00:00 2001 From: scratko Date: Thu, 18 Apr 2024 20:05:03 +0300 Subject: Release version --- Makefile | 2 +- color_palette.c | 9 ++- color_palette.h | 3 +- field.c | 94 ++++++++++++++++------ field.h | 15 ++-- ghosts.c | 12 --- ghosts.h | 1 - pac.c | 7 -- pacman.c | 242 +++++++++++++++++++++++++++++++++++++------------------- 9 files changed, 252 insertions(+), 133 deletions(-) diff --git a/Makefile b/Makefile index 12433c4..b53c2b4 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ SRCMODULES = field.c ghosts.c pac.c queue.c color_palette.c pacman.c OBJMODULES = $(SRCMODULES:.c=.o) CC = gcc -CFLAGS = -Wall -g -c -D DEBUG +CFLAGS = -Wall -g -c LIBS = -lncurses -lm diff --git a/color_palette.c b/color_palette.c index e839e8b..0d1a959 100644 --- a/color_palette.c +++ b/color_palette.c @@ -10,6 +10,7 @@ void set_pairs() init_pair(6, COLOR_RED, COLOR_BLACK); init_pair(7, COLOR_BLUE, COLOR_BLACK); init_pair(8, COLOR_MAGENTA, COLOR_BLACK); + init_pair(9, COLOR_BLUE, COLOR_WHITE); } void paint_field_element(int element) @@ -34,9 +35,15 @@ void paint_stats() attrset(COLOR_PAIR(5)); } -void paint_ghost(enum ghost_color color, int blink) +void paint_ghost(enum ghost_color color, int frightened_counter, + int prison_status) { int attr; + if(frightened_counter && !prison_status) { + attr = COLOR_PAIR(9); + attrset(attr); + return; + } switch(color) { case red: attr = COLOR_PAIR(6); diff --git a/color_palette.h b/color_palette.h index 81ccce8..72f10a3 100644 --- a/color_palette.h +++ b/color_palette.h @@ -7,7 +7,8 @@ void set_pairs(); void paint_field_element(int element); void paint_stats(); -void paint_ghost(enum ghost_color color, int blink); +void paint_ghost(enum ghost_color color, int frightened_counter, + int prison_status); void paint_pac(); void paint_hit(); void reset_attr(); diff --git a/field.c b/field.c index f0190e9..fd31606 100644 --- a/field.c +++ b/field.c @@ -5,6 +5,8 @@ #include #include "color_palette.h" +enum { frightened_limit = 50 }; + static const char field_sample[field_height][field_width] = { {"////////////////////////////"}, {"/1....2.....1//1.....2....1/"}, @@ -35,7 +37,7 @@ static const char field_sample[field_height][field_width] = { {"/.//////////.//.//////////./"}, {"/1..........2..2..........1/"}, {"////////////////////////////"}, - {" C C Score: "} + {" C C Score: /243"} }; static void copy_field(game_space field) @@ -55,10 +57,10 @@ game_space get_new_field() return field; } -void clear_field(game_space field) +void clear_field(game_space *field) { - free(field); - field = NULL; + free(*field); + *field = NULL; } static int field_has_coin(int x, int y) @@ -107,6 +109,11 @@ void print_field(game_space field) for(j = 0; j < field_width; ++j) { symbol = field[i][j]; move(i, j); + if(i == field_height-1) { + symbol != ' ' ? paint_stats() : reset_attr(); + addch(symbol); + continue; + } if(is_coin_symbol(symbol, j, i) && field_has_coin(j, i)) { paint_field_element(coin); symbol == energizer ? addch('*') : addch('.'); @@ -123,11 +130,6 @@ void print_field(game_space field) paint_field_element(block); addch(' '); break; -#if 0 - case energizer: - addch('*'); - break; -#endif case door: paint_field_element(door); addch(' '); @@ -146,41 +148,79 @@ void print_field(game_space field) } } -void display_character(int y, int x, enum select_character symbol) +static int is_countdown(int timer, int prison_status) +{ + return (timer <= frightened_limit && timer > frightened_limit-10) && + !prison_status; +} + +void display_character(int y, int x, int symbol, int prison_status) { move(y, x); - if(symbol == pac_char) + if((enum select_character) symbol == pac_char) { paint_pac(); - addch(symbol); + addch(symbol); + refresh(); + return; + } + if((enum select_character) symbol != ghost_char) + is_countdown(symbol, prison_status) ? + printw("%d", frightened_limit - symbol) : addch(ghost_char); + else + addch(ghost_char); refresh(); } void display_ghosts_on_field(struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, - struct ghost_type *orange_ghost) + struct ghost_type *orange_ghost, + int frightened_counter) { - paint_ghost(red_ghost->color, red_ghost->frightened_status); - display_character(red_ghost->position.y, red_ghost->position.x, ghost_char); - paint_ghost(pink_ghost->color, pink_ghost->frightened_status); + paint_ghost(red_ghost->color, frightened_counter, + red_ghost->prison_params.active); + display_character(red_ghost->position.y, red_ghost->position.x, + frightened_counter ? frightened_counter : ghost_char, + red_ghost->prison_params.active); + + paint_ghost(pink_ghost->color, frightened_counter, + pink_ghost->prison_params.active); display_character(pink_ghost->position.y, pink_ghost->position.x, - ghost_char); - paint_ghost(blue_ghost->color, blue_ghost->frightened_status); + frightened_counter ? frightened_counter : ghost_char, + pink_ghost->prison_params.active); + + paint_ghost(blue_ghost->color, frightened_counter, + blue_ghost->prison_params.active); display_character(blue_ghost->position.y, blue_ghost->position.x, - ghost_char); - paint_ghost(orange_ghost->color, orange_ghost->frightened_status); + frightened_counter ? frightened_counter : ghost_char, + blue_ghost->prison_params.active); + + paint_ghost(orange_ghost->color, frightened_counter, + orange_ghost->prison_params.active); display_character(orange_ghost->position.y, orange_ghost->position.x, - ghost_char); + frightened_counter ? frightened_counter : ghost_char, + orange_ghost->prison_params.active); } void display_score(int value) { - move(field_height-1, 25); + move(field_height-1, 21); paint_stats(); printw("%d", value); refresh(); } +void display_ready() +{ + move(17, 11); + /* + * the same color as pacman + */ + paint_pac(); + printw("READY!"); + refresh(); +} + void clear_or_revert_symbol(const game_space field, struct coordinates position, enum select_character character, const struct queue *eaten_coins) @@ -193,7 +233,7 @@ void clear_or_revert_symbol(const game_space field, struct coordinates position, if(character == ghost_char) { if(is_coin_symbol(symbol, x, y) && field_has_coin(x, y) && !queue_consists_point(eaten_coins, position)) { - if(symbol == energizer && field_has_energizer(field, x, y)) { + if(symbol == energizer) { paint_field_element(coin); addch('*'); } else { @@ -295,6 +335,14 @@ void clear_energizer(game_space field, struct coordinates point) field[y][x] = ' '; } +void clear_ready() +{ + move(17, 11); + reset_attr(); + printw(" "); + refresh(); +} + int is_equal_points(struct coordinates first_point, struct coordinates second_point) { diff --git a/field.h b/field.h index c527309..728d75a 100644 --- a/field.h +++ b/field.h @@ -37,14 +37,17 @@ struct free_directions { void print_field(game_space field); -void display_character(int y, int x, enum select_character symbol); +void display_character(int y, int x, int symbol, int prison_status); struct ghost_type; void display_ghosts_on_field(struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, - struct ghost_type *orange_ghost); + struct ghost_type *orange_ghost, + int frightened_counter); void display_score(int value); +void display_ready(); + struct coordinates; void display_hit(struct coordinates pac_position, const struct ghost_type *red_ghost, @@ -57,6 +60,10 @@ void clear_or_revert_symbol(game_space field, struct coordinates position, enum select_character character, const struct queue *eaten_coins); +void clear_energizer(game_space field, struct coordinates point); +void clear_field(game_space *field); +void clear_ready(); + enum intersection_type get_intersection(const game_space field, struct ghost_type *ghost); @@ -72,13 +79,9 @@ int field_has_energizer(const game_space field, int x, int y); void change_point_if_outside_tunnel(struct coordinates *point); -void clear_energizer(game_space field, struct coordinates point); - int is_equal_points(struct coordinates first_point, struct coordinates second_point); -void clear_field(game_space field); - void erase_life(int value); void erase_hit(struct coordinates point); diff --git a/ghosts.c b/ghosts.c index 5c60200..72e4f81 100644 --- a/ghosts.c +++ b/ghosts.c @@ -48,7 +48,6 @@ void initialize_ghost(struct ghost_type *ghost, enum ghost_color color) ghost->prison_params.position.y = orange_prison_y; break; } - ghost->frightened_status = 0; ghost->direction = none; ghost->prison_params.prison_counter = 0; ghost->prison_params.active = 0; @@ -448,17 +447,6 @@ void reverse_all_ghosts(struct ghost_type *red_ghost, left : orange_ghost->direction ^ 1; } -void set_frightened_status(int status, struct ghost_type *red_ghost, - struct ghost_type *pink_ghost, - struct ghost_type *blue_ghost, - struct ghost_type *orange_ghost) -{ - red_ghost->frightened_status = status; - pink_ghost->frightened_status = status; - blue_ghost->frightened_status = status; - orange_ghost->frightened_status = status; -} - int is_pac_nearby(struct pacman pac, struct ghost_type ghost) { if(ghost.capture_info.status) diff --git a/ghosts.h b/ghosts.h index ff8eb75..df5487e 100644 --- a/ghosts.h +++ b/ghosts.h @@ -59,7 +59,6 @@ struct ghost_type { struct coordinates position; struct coordinates home_position; enum ghost_color color; - int frightened_status; enum movement_direction direction; struct prison prison_params; struct capture capture_info; diff --git a/pac.c b/pac.c index 2aac83c..d3aa96c 100644 --- a/pac.c +++ b/pac.c @@ -141,11 +141,4 @@ void catch_pac(struct pacman *pac) --pac->lives; erase_life(pac->lives); pac->direction = none; -#if 0 - if(pac->lives >= 0) { - pac->position.y = pac_y; - pac->position.x = pac_x; - pac->direction = none; - } -#endif } diff --git a/pacman.c b/pacman.c index ce2fd5d..15a4b63 100644 --- a/pacman.c +++ b/pacman.c @@ -7,15 +7,17 @@ #include #include #include +#include enum { timeout_duration = 0, sleep_duration = 120000, key_escape = 27, + whitespace = 32, max_get_out_stage = 6, - chase_move_limit = 70, - scatter_move_limit = 35, - frightened_move_limit = 50, + chase_limit = 70, + scatter_limit = 35, + fright_limit = 50, phase_limit = 4, prison_limit = 30, max_score = 243 @@ -23,9 +25,9 @@ enum { struct mode_type { enum behavior_mode current_mode; - int chase_count; - int scatter_count; - int frightened_count; + int chase_counter; + int scatter_counter; + int fright_counter; int phase_number; int reverse_direction; int get_out_stage; @@ -50,9 +52,9 @@ static void initialize_ghosts(struct ghost_type *red_ghost, 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->chase_counter = 0; + mode_params->scatter_counter = 0; + mode_params->fright_counter = 0; mode_params->phase_number = 0; mode_params->reverse_direction = 0; mode_params->get_out_stage = max_get_out_stage; @@ -73,8 +75,8 @@ static void initialize_params(game_space *field, struct queue *eaten_coins, 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); + orange_ghost, mode_params->fright_counter); + display_character(pac->position.y, pac->position.x, pac_char, 0); } static int is_up_move_blocked(const struct ghost_type *ghost, @@ -182,16 +184,28 @@ static void random_pathfinder_stage(game_space field, } } -static void change_mode(struct mode_type *mode_params) +static void change_mode(struct mode_type *mode_params, struct pacman *pac) { + 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->fright_counter = 0; + return; + } + /* + * After all phases are completed, you can only change the mode here from + * frightened to chase. + */ 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) { + if(mode_params->chase_counter > chase_limit) { mode_params->current_mode = scatter; - mode_params->chase_count = 0; + mode_params->chase_counter = 0; ++mode_params->phase_number; if(mode_params->phase_number == phase_limit) mode_params->current_mode = chase; @@ -200,26 +214,25 @@ static void change_mode(struct mode_type *mode_params) } break; case scatter: - if(mode_params->scatter_count > scatter_move_limit) { + if(mode_params->scatter_counter > scatter_limit) { mode_params->current_mode = chase; - mode_params->scatter_count = 0; + mode_params->scatter_counter = 0; ++mode_params->reverse_direction; } break; case frightened: - if(mode_params->frightened_count > frightened_move_limit) { + if(mode_params->fright_counter > fright_limit) { mode_params->current_mode = - mode_params->chase_count || mode_params->phase_number == - phase_limit ? chase : scatter; - mode_params->frightened_count = 0; + mode_params->chase_counter || + (mode_params->phase_number == phase_limit) ? chase : scatter; + mode_params->fright_counter = 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 pacman *pac, struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) @@ -227,13 +240,13 @@ static void chase_mode(game_space field, struct mode_type *mode_params, 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); + ++mode_params->chase_counter; + change_mode(mode_params, pac); } } static void scatter_mode(game_space field, struct mode_type *mode_params, - struct ghost_type *red_ghost, + struct pacman *pac, struct ghost_type *red_ghost, struct ghost_type *pink_ghost, struct ghost_type *blue_ghost, struct ghost_type *orange_ghost) @@ -241,23 +254,21 @@ static void scatter_mode(game_space field, struct mode_type *mode_params, 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); + ++mode_params->scatter_counter; + change_mode(mode_params, pac); } } static void frightened_mode(game_space field, struct mode_type *mode_params, - struct ghost_type *red_ghost, + struct pacman *pac, 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); + ++mode_params->fright_counter; + change_mode(mode_params, pac); } static int is_outside_prison(struct ghost_type ghost) @@ -365,11 +376,6 @@ static void catching_stage(game_space field, 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) @@ -377,6 +383,9 @@ static void catching_stage(game_space field, } } +/* + * to recognize a hit and also to start a new attempt + */ static int ghost_caught_pacman(struct ghost_type red_ghost, struct ghost_type pink_ghost, struct ghost_type blue_ghost, @@ -408,14 +417,93 @@ static void final_stage(struct game_params_type *game_options, int win) game_options->exit = (key == 'y') ? 0 : 1; } -static void clear_field_and_queue(game_space field, struct queue *eaten_coins) +/* + * restart after winning or losing + */ + +static void clear_field_and_queue(game_space *field, struct queue *eaten_coins) { clear_field(field); queue_clear(eaten_coins); } +static void new_game(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) +{ + clear_field_and_queue(field, eaten_coins); + initialize_params(field, eaten_coins, mode_params, pac, red_ghost, + pink_ghost, blue_ghost, orange_ghost); + +} + +static void new_attempt(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) +{ + 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, + mode_params->fright_counter); + display_character(pac->position.y, pac->position.x, pac_char, 0); +} + +static void waiting_for_readiness() +{ + display_ready(); + usleep(sleep_duration*5); + clear_ready(); +} + +static void set_pause(struct game_params_type *game_options) +{ + int key; + timeout(-1); + while((key = getch()) != whitespace && key != key_escape) + ; + if(key == whitespace) + game_options->pause = 1; + else + game_options->exit = 1; + timeout(timeout_duration); +} + +static void help_message() +{ + fprintf(stderr, + "Sorry.\n" + "To play Pacman for Console, your console window must be\n" + "at least 28x30. Please resize your window/resolution and\n" + "re-run the game.\n" + ); +} + +static int check_screen_resolution() +{ + initscr(); + int row, col; + getmaxyx(stdscr, row, col); + endwin(); + return row >= field_height && col >= field_width; +} + int main() { + if(!check_screen_resolution()) { + help_message(); + return 1; + } game_space field = NULL; struct ghost_type red_ghost, pink_ghost, blue_ghost, orange_ghost; struct pacman pac; @@ -437,8 +525,19 @@ int main() game_options.pause = 0; initialize_params(&field, &eaten_coins, &mode_params, &pac, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); - usleep(sleep_duration); + waiting_for_readiness(); while((key = getch()) != key_escape) { + /* + * pause + */ + if(key == whitespace) { + set_pause(&game_options); + if(game_options.pause) { + game_options.pause = 0; + continue; + } else + break; + } /* * pacman */ @@ -447,13 +546,8 @@ int main() 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; - } + if(pac.is_energizer_eaten) + change_mode(&mode_params, &pac); /* * ghosts */ @@ -469,10 +563,10 @@ int main() 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, + scatter_mode(field, &mode_params, &pac, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); else if(mode_params.current_mode == frightened) - frightened_mode(field, &mode_params, &red_ghost, &pink_ghost, + frightened_mode(field, &mode_params, &pac, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost); make_ghost_moves(field, &red_ghost, &pink_ghost, &blue_ghost, &orange_ghost, &eaten_coins); @@ -486,71 +580,57 @@ int main() */ display_score(pac.score); display_ghosts_on_field(&red_ghost, &pink_ghost, &blue_ghost, - &orange_ghost); + &orange_ghost, mode_params.fright_counter); 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); + display_character(pac.position.y, pac.position.x, pac_char, 0); 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); + printw("CHASE %d ", mode_params.chase_counter); else if(mode_params.current_mode == scatter) - printw("SCATTER %d ", mode_params.scatter_count); + printw("SCATTER %d ", mode_params.scatter_counter); else if(mode_params.current_mode == frightened) - printw("FRIGHTENED %d ", mode_params.frightened_count); + printw("FRIGHTENED %d ", mode_params.fright_counter); 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 + /* + * result check + */ 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); + new_game(&field, &eaten_coins, &mode_params, &pac, &red_ghost, + &pink_ghost, &blue_ghost, &orange_ghost); + waiting_for_readiness(); } continue; } + /* + a new attempt if pacman has any life + */ 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); + stored_direction = none; + new_attempt(&field, &eaten_coins, &mode_params, &pac, &red_ghost, + &pink_ghost, &blue_ghost, &orange_ghost); + waiting_for_readiness(); } } - clear_field_and_queue(field, &eaten_coins); + clear_field_and_queue(&field, &eaten_coins); endwin(); return 0; } -- cgit v1.2.3