diff --git a/Makefile b/Makefile index 5618a70..3ec11c4 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = gcc CFLAGS = -std=c11 -Wextra -Wpedantic -g3 -fsanitize=address -LDFLAGS = -lncursesw -fsanitize=address +LDFLAGS = -lncurses -fsanitize=address SRC = $(filter-out voorbeeld.c,$(wildcard *.c)) HEADERS = $(wildcard *.h) diff --git a/assets/handleiding.txt b/assets/handleiding.txt new file mode 100644 index 0000000..8e81adc --- /dev/null +++ b/assets/handleiding.txt @@ -0,0 +1,75 @@ +*--------------------------------------------* +| | +| !!! HOWTO MINIGAME !!! | +| | +| *________________* | +| |--- MANUAL ---| | +| *------------------------------------* | +| | | | +| | Exit: | | +| | Escape, backspace | | +| | | | +| *------------------------------------* | +| | +| *________________* | +| |---- MENU ----| | +| *------------------------------------* | +| | | | +| | Move down: | | +| | 's', arrow_down | | +| | | | +| | Move up: | | +| | 'w', arrow_up | | +| | | | +| | Select: | | +| | 'f', enter, space bar | | +| | | | +| | Exit: | | +| | Escape, backspace | | +| | | | +| *------------------------------------* | +| | +| *-----------------* | +| |- MAZE RUNNER -| | +| *------------------------------------* | +| | | | +| | Move up: | | +| | 'w', arrow_up | | +| | | | +| | Move down: | | +| | 's', arrow_down | | +| | | | +| | Move right: | | +| | 'd', arrow_right | | +| | | | +| | Move left: | | +| | 'a', arrow_left | | +| | | | +| | Exit: | | +| | Escape, backspace | | +| | | | +| *------------------------------------* | +| | +| *-----------------* | +| |---- SNAKE ----| | +| *------------------------------------* | +| | | | +| | Turn up: | | +| | 'w', arrow_up | | +| | | | +| | Turn down: | | +| | 's', arrow_down | | +| | | | +| | Turn right: | | +| | 'd', arrow_right | | +| | | | +| | Turn left: | | +| | 'a', arrow_left | | +| | | | +| | Exit: | | +| | Escape, backspace | | +| | | | +| *------------------------------------* | +*--------------------------------------------* +1234567890123456789012345678901234567890123456 + 10 20 30 40 | diff --git a/deel2.tar.gz b/deel2.tar.gz deleted file mode 100644 index 702ab9f..0000000 Binary files a/deel2.tar.gz and /dev/null differ diff --git a/grid_game_engine.c b/grid_game_engine.c index b807a66..9f1401b 100644 --- a/grid_game_engine.c +++ b/grid_game_engine.c @@ -12,7 +12,7 @@ #include "rooster.h" -int same_coordinate(coordinate a, coordinate b) { +int same_coordinate(const coordinate a, const coordinate b) { return a.x == b.x && a.y == b.y; } @@ -35,12 +35,12 @@ void show_grid_on_offset(const rooster *gp, const int starting_x, const int star refresh(); } -void show_grid(const rooster *rp) { - show_grid_on_offset(rp, 0, 0); +void show_grid(const rooster *gp) { + show_grid_on_offset(gp, 0, 0); } -void update_grid(rooster *rp, char c, int x, int y) { - if (rooster_plaats(rp, x, y, c) == 1) { +void update_grid(rooster *gp, const char c, const int x, const int y) { + if (rooster_plaats(gp, x, y, c) == 1) { mvaddch(y, x, c); } } @@ -51,9 +51,9 @@ void update_grid(rooster *rp, char c, int x, int y) { * Side Effect: * Clears the console and prints the victory message. */ -static void display_victory(void) { +static void display_victory(const coordinate location) { erase(); - mvprintw(2,5, "YOU WON!!!!!"); + mvprintw(location.y, location.x, "YOU WON!!!!!"); refresh(); } @@ -63,9 +63,9 @@ static void display_victory(void) { * Side Effect: * Clears the console and prints the GAME OVER message. */ -static void display_loss(void) { +static void display_loss(const coordinate location) { erase(); - mvprintw(2,5, "GAME OVER"); + mvprintw(location.y, location.x, "GAME OVER"); refresh(); } @@ -75,9 +75,9 @@ static void display_loss(void) { * Side Effect: * Clears the console and prints the quit message. */ -static void display_quit(void) { +static void display_quit(const coordinate location) { erase(); - mvprintw(2,5, "You quit the game"); + mvprintw(location.y, location.x, "You quit the game"); refresh(); } @@ -87,42 +87,46 @@ static void display_quit(void) { * Side Effect: * Clears the console and prints the hacker man message. */ -static void display_hackerman(void) { +static void display_hackerman(const coordinate location) { erase(); - mvprintw(2,5, "The hacker man strikes again..."); + mvprintw(location.y, location.x, "The hacker man strikes again..."); refresh(); } -void graceful_exit(void) { - mvprintw(25, 5, "Press 'q' to exit."); +void graceful_exit(const coordinate message_location) { + mvprintw(message_location.y, message_location.x, "Press ENTER or SPACE to exit."); while (1) { switch (getch()) { - case 'q': - case 'Q': + case KEY_ENTER: + case '\n': + case ' ': return; } } } -void game_exit_screen(rooster *gp) { - toestand current_state = rooster_vraag_toestand(gp); +void game_exit_screen(const rooster *gp, coordinate location) { + const toestand current_state = rooster_vraag_toestand(gp); switch (current_state) { case STATE_GEWONNEN: - display_victory(); + display_victory(location); break; case STATE_VERLOREN: - display_loss(); + display_loss(location); break; case STATE_QUIT: - display_quit(); + display_quit(location); break; default: - display_hackerman(); + display_hackerman(location); } - graceful_exit(); + + location.y += 2; + graceful_exit(location); } static void init_ncurses() { + ESCDELAY = 0; setlocale(LC_ALL, ""); initscr(); cbreak(); // So you can cancel the game with ctrl + c. diff --git a/grid_game_engine.h b/grid_game_engine.h index 2f07c96..988c574 100644 --- a/grid_game_engine.h +++ b/grid_game_engine.h @@ -2,7 +2,7 @@ * Created by snapshot112 on 10/15/25. * * A game engine that uses the can run and display games in rectangular grids. - * The graphics are made using ncursesw. + * The graphics are made using ncurses. * * Please make sure to initialize the game engine before running any games. */ @@ -11,6 +11,8 @@ #define MINIGAME_MENU_GRID_GAME_ENGINE_H #include "rooster.h" +#define KEY_ESCAPE 27 + typedef struct { int x; int y; @@ -92,25 +94,29 @@ void update_grid(rooster *gp, char c, int x, int y); * Display the ending screen that matches the end state of the grid. * * Input: - * gp: A pointer to the grid. + * gp: A pointer to the grid. + * coordinate: The location to show the ending screen. * * Side Effects: * The end of game screen gets displayed with a graceful exit. */ -void game_exit_screen(rooster *gp); +void game_exit_screen(const rooster *gp, coordinate location); /* - * Waits for you to press 'q' before exiting the game. + * Waits for you to press ENTER or SPACE before exiting the game. * - * Side effect: Prints "Press 'q' to exit." game to the console. + * Input: + * coordinate: The location to show the message. + * + * Side effect: Prints "Press ENTER or SPACE to exit." game to the console. */ -void graceful_exit(void); +void graceful_exit(coordinate message_location); /* * Initialize ncurses. * * This enables cbreak, noecho, hides the cursor and enables the extra keys. - * This also creates the color pairs needed for game_colors, + * This also creates the color pairs needed for game_colors and sets ESCDELAY to 0. */ void init_engine(void); diff --git a/manual.c b/manual.c new file mode 100644 index 0000000..0655140 --- /dev/null +++ b/manual.c @@ -0,0 +1,33 @@ +// +// Created by snapshot112 on 10/17/25. +// + +#include "manual.h" + +#include + +#include "rooster.h" + +void manual(const coordinate display_location) { + erase(); + FILE *fp = fopen("assets/handleiding.txt", "r"); + if (fp == NULL) { + return; + } + + rooster *grid = grid_from_file(fp); + if (grid == NULL) { + mvaddstr(display_location.y, display_location.x, "Error loading grid"); + return; + } + + fclose(fp); + show_grid_on_offset(grid, display_location.x, display_location.y); + + rooster_klaar(grid); + + int ch = getch(); + while (ch != KEY_ESCAPE && ch != KEY_BACKSPACE && ch != ' ') { + ch = getch(); + } +} diff --git a/manual.h b/manual.h new file mode 100644 index 0000000..da8d146 --- /dev/null +++ b/manual.h @@ -0,0 +1,27 @@ +/* + * Created by snapshot112 on 10/15/25. + * + * Display the manual for the minigames + */ + +#ifndef MINIGAME_MENU_MANUAL_H +#define MINIGAME_MENU_MANUAL_H +#include "grid_game_engine.h" + +/* + * A game manual for the minigames menu. + * + * Please make sure to include and initialize the game engine before opening the manual + * + * Input: + * display_location: The location to display the manual. + * + * Side Effects: + * Clears the console and uses it to display the manual. + * + * Controls: + * Press ESCAPE or ENTER to exit the manual. + */ +void manual(coordinate display_location); + +#endif //MINIGAME_MENU_MANUAL_H diff --git a/maze_runner.c b/maze_runner.c index 6c12962..332a84d 100644 --- a/maze_runner.c +++ b/maze_runner.c @@ -105,7 +105,9 @@ static void speel_maze(rooster *rp) { case 'D': maze_runner_beweeg(rp, 1, 0); break; + case 'p': case KEY_BACKSPACE: + case KEY_ESCAPE: rooster_zet_toestand(rp, STATE_QUIT); break; } @@ -126,6 +128,6 @@ void maze_runner(void) { } // Exit game. - game_exit_screen(rp); + game_exit_screen(rp, (coordinate){0, 0}); rooster_klaar(rp); } diff --git a/minesweeper.c b/minesweeper.c index 60274ea..c59858f 100644 --- a/minesweeper.c +++ b/minesweeper.c @@ -11,6 +11,6 @@ void minesweeper() { clear(); mvprintw(0,0, "Minesweeper has not yet been created"); - graceful_exit(); + graceful_exit((coordinate){0, 3}); refresh(); } diff --git a/minigame_menu.c b/minigame_menu.c index 405f8f8..4bb6c67 100644 --- a/minigame_menu.c +++ b/minigame_menu.c @@ -8,14 +8,23 @@ #include #include "grid_game_engine.h" +#include "manual.h" #include "maze_runner.h" #include "minesweeper.h" #include "rooster.h" #include "snake.h" -#define AMOUNT_OF_MENU_OPTIONS 4 +#define AMOUNT_OF_MENU_OPTIONS 5 -static game SELECTED_GAME = GAME_MAZE_RUNNER; +typedef enum { + GAME_HELP = 0, + GAME_MAZE_RUNNER = 1, + GAME_SNAKE = 2, + GAME_MINESWEEPER = 3, + GAME_QUIT = 4, +} game; + +static game SELECTED_GAME = GAME_HELP; static int OFFSET_Y = 5; static int OFFSET_X = 5; @@ -28,6 +37,9 @@ static int OFFSET_X = 5; */ static void launch_game(const game game) { switch (game) { + case GAME_HELP: + manual((coordinate){0,0}); + break; case GAME_MAZE_RUNNER: maze_runner(); break; @@ -55,6 +67,7 @@ static void launch_game(const game game) { */ static void menu_highlight(const rooster *menu) { switch (SELECTED_GAME) { + case GAME_HELP: case GAME_MAZE_RUNNER: case GAME_SNAKE: case GAME_MINESWEEPER: @@ -82,7 +95,7 @@ static void menu_highlight(const rooster *menu) { * Displays the menu */ static void show_menu(const rooster *menu) { - clear(); + erase(); show_grid_on_offset(menu, OFFSET_X, OFFSET_Y); menu_highlight(menu); refresh(); @@ -118,7 +131,7 @@ static void menu_move(const int offset) { * Side Effect: * Changes the SELECTED_GAME as needed and launches selected games on select. */ -static int navigate_menu(rooster *menu) { +static int navigate_menu(void) { switch (getch()) { case KEY_UP: case 'w': @@ -134,12 +147,15 @@ static int navigate_menu(rooster *menu) { case '\n': case 'f': case 'F': + case ' ': if (SELECTED_GAME == GAME_QUIT) { return 1; } launch_game(SELECTED_GAME); break; + case 'p': case KEY_BACKSPACE: + case KEY_ESCAPE: return 1; } return 0; @@ -152,7 +168,8 @@ static int navigate_menu(rooster *menu) { * A pointer to the menu grid. */ static rooster *initialize_menu(void) { - char menu[] = "Maze Runner\n" + char menu[] = "How to play\n" + "Maze Runner\n" " Snake \n" "Minesweeper\n" " Leave \n"; @@ -165,7 +182,7 @@ void minigame_menu(void) { while (true) { show_menu(menu); - if (navigate_menu(menu) == 1) { + if (navigate_menu() == 1) { break; } } diff --git a/minigame_menu.h b/minigame_menu.h index 5c4c3cd..7800f5a 100644 --- a/minigame_menu.h +++ b/minigame_menu.h @@ -9,13 +9,6 @@ #ifndef MINIGAME_MENU_MINIGAME_MENU_H #define MINIGAME_MENU_MINIGAME_MENU_H -typedef enum { - GAME_MAZE_RUNNER = 0, - GAME_SNAKE = 1, - GAME_MINESWEEPER = 2, - GAME_QUIT = 3, -} game; - /* * A minigame menu for games configured to run on the grid game engine. * diff --git a/rooster.c b/rooster.c index aeec8ae..5b59deb 100644 --- a/rooster.c +++ b/rooster.c @@ -1,6 +1,5 @@ #include "rooster.h" -#include #include #include #include @@ -89,7 +88,7 @@ static int get_grid_sizes(FILE *fh, rooster *rost) { return 0; } - rost->height = (int)ftell(fh) / (int)sizeof(char) / rost->width; + rost->height = (int)ftell(fh) / (int)sizeof(char) / (rost->width + 1); fseek(fh, 0, SEEK_SET); return 1; diff --git a/snake.c b/snake.c index 0c44535..b298c98 100644 --- a/snake.c +++ b/snake.c @@ -244,7 +244,7 @@ static void update_snake(coordinate new_head, snake_action action) { static void *snake_move(void *arg) { struct timespec timer; timer.tv_sec = 0; - timer.tv_nsec = 250000000L; + timer.tv_nsec = 250000000L; // Snake moves every 0.25 seconds. while (rooster_vraag_toestand(GRID) == STATE_AAN_HET_SPELEN) { nanosleep(&timer, NULL); @@ -311,6 +311,7 @@ static void *play_snake(void *arg) { turn_snake(DIRECTION_RIGHT); break; case KEY_BACKSPACE: + case KEY_ESCAPE: rooster_zet_toestand(GRID, STATE_QUIT); break; } @@ -352,5 +353,5 @@ void snake(void) { pthread_mutex_destroy(&MUTEX); rooster_klaar(GRID); - graceful_exit(); + graceful_exit(MESSAGE_LOCATION); } diff --git a/spel b/spel index 5b6dd84..9feb65c 100755 Binary files a/spel and b/spel differ diff --git a/spel.c b/spel.c index 32031a0..0ffc4bb 100644 --- a/spel.c +++ b/spel.c @@ -12,12 +12,14 @@ */ #include "grid_game_engine.h" +#include "manual.h" #include "minigame_menu.h" int main(void) { init_engine(); - // 5. Speel het spel. + // Speel het spel. + // manual((coordinate){0,3}); minigame_menu(); cleanup_engine();